Catatan: Kami merekomendasikan WorkManager sebagai solusi untuk sebagian besar kasus penggunaan pemrosesan di latar belakang. Harap baca panduan pemrosesan di latar belakang untuk mengetahui solusi terbaik bagi Anda.
Komponen adaptor sinkronisasi di aplikasi Anda merangkum kode untuk tugas yang mentransfer data antara perangkat dan server. Berdasarkan penjadwalan dan pemicu yang Anda berikan dalam aplikasi, framework adaptor sinkronisasi menjalankan kode di komponen adaptor sinkronisasi. Untuk menambahkan komponen adaptor sinkronisasi ke aplikasi, Anda perlu menambahkan bagian berikut:
- Class adaptor sinkronisasi.
- Class yang menggabungkan kode transfer data Anda dalam antarmuka yang kompatibel dengan framework adaptor sinkronisasi.
-
Batas
Service
. - Komponen yang memungkinkan framework adaptor sinkronisasi untuk menjalankan kode di class adaptor sinkronisasi Anda.
- File metadata XML adaptor sinkronisasi.
- File yang berisi informasi tentang adaptor sinkronisasi Anda. Framework akan membaca file ini untuk mengetahui cara memuat dan menjadwalkan transfer data Anda.
- Deklarasi di manifes aplikasi.
- XML yang mendeklarasikan layanan terikat dan titik untuk menyinkronkan metadata khusus adaptor.
Tutorial ini menunjukkan cara mendefinisikan elemen ini.
Membuat class adaptor sinkronisasi
Di bagian tutorial ini, Anda akan mempelajari cara membuat class adaptor sinkronisasi yang mengenkapsulasi kode transfer data. Pembuatan class mencakup perluasan class dasar adaptor sinkronisasi, menentukan konstruktor untuk class, dan mengimplementasikan metode tempat Anda menetapkan tugas transfer data.
Memperluas class adaptor sinkronisasi dasar
Untuk membuat komponen adaptor sinkronisasi, mulailah dengan memperluas AbstractThreadedSyncAdapter
dan menulis konstruktornya. Gunakan konstruktor untuk menjalankan tugas penyiapan setiap kali komponen adaptor sinkronisasi Anda dibuat dari awal, sama seperti Anda menggunakan Activity.onCreate()
untuk menyiapkan suatu aktivitas. Misalnya, jika aplikasi Anda menggunakan penyedia konten untuk menyimpan data, gunakan konstruktor untuk mendapatkan instance ContentResolver
. Karena bentuk konstruktor kedua ditambahkan dalam platform Android versi 3.0 untuk mendukung argumen parallelSyncs
, Anda harus membuat dua bentuk konstruktor guna mempertahankan kompatibilitas.
Catatan: Framework adaptor sinkronisasi dirancang untuk berfungsi dengan komponen adaptor sinkronisasi yang merupakan instance singleton. Pembuatan instance komponen adaptor sinkronisasi dibahas secara lebih mendetail di bagian Mengikat Adaptor Sinkronisasi ke Framework.
Contoh berikut menunjukkan cara menerapkan
AbstractThreadedSyncAdapter
beserta konstruktornya:
Kotlin
/** * Handle the transfer of data between a server and an * app, using the Android sync adapter framework. */ class SyncAdapter @JvmOverloads constructor( context: Context, autoInitialize: Boolean, /** * Using a default argument along with @JvmOverloads * generates constructor for both method signatures to maintain compatibility * with Android 3.0 and later platform versions */ allowParallelSyncs: Boolean = false, /* * If your app uses a content resolver, get an instance of it * from the incoming Context */ val mContentResolver: ContentResolver = context.contentResolver ) : AbstractThreadedSyncAdapter(context, autoInitialize, allowParallelSyncs) { ... }
Java
/** * Handle the transfer of data between a server and an * app, using the Android sync adapter framework. */ public class SyncAdapter extends AbstractThreadedSyncAdapter { ... // Global variables // Define a variable to contain a content resolver instance ContentResolver contentResolver; /** * Set up the sync adapter */ public SyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); /* * If your app uses a content resolver, get an instance of it * from the incoming Context */ contentResolver = context.getContentResolver(); } ... /** * Set up the sync adapter. This form of the * constructor maintains compatibility with Android 3.0 * and later platform versions */ public SyncAdapter( Context context, boolean autoInitialize, boolean allowParallelSyncs) { super(context, autoInitialize, allowParallelSyncs); /* * If your app uses a content resolver, get an instance of it * from the incoming Context */ contentResolver = context.getContentResolver(); ... }
Menambahkan kode transfer data
Komponen adaptor sinkronisasi tidak otomatis melakukan transfer data. Sebaliknya, framework akan
merangkum kode transfer data Anda, sehingga framework adaptor sinkronisasi dapat menjalankan
transfer data di latar belakang, tanpa keterlibatan dari aplikasi Anda. Jika sudah siap
menyinkronkan data aplikasi Anda, framework akan memanggil implementasi metode
onPerformSync()
.
Untuk memfasilitasi transfer data dari kode aplikasi utama ke komponen adaptor sinkronisasi, framework adaptor sinkronisasi akan memanggil onPerformSync()
dengan argumen berikut:
- Akun
- Objek
Account
yang berkaitan dengan peristiwa yang memicu adaptor sinkronisasi. Jika server Anda tidak menggunakan akun, Anda tidak perlu menggunakan informasi dalam objek ini. - Konten bonus
-
Bundle
yang berisi tanda dikirim oleh peristiwa yang memicu adaptor sinkronisasi. - Otoritas
- Otoritas penyedia konten dalam sistem. Aplikasi Anda harus memiliki akses ke penyedia ini. Biasanya, otoritas sesuai dengan penyedia konten di aplikasi Anda sendiri.
- Klien penyedia konten
-
ContentProviderClient
untuk penyedia konten yang ditunjuk oleh argumen otoritas.ContentProviderClient
adalah antarmuka publik yang ringan untuk penyedia konten. Class ini memiliki fungsi dasar yang sama denganContentResolver
. Jika menggunakan penyedia konten untuk menyimpan data bagi aplikasi, Anda dapat terhubung ke penyedia dengan objek ini. Jika tidak, Anda dapat mengabaikannya. - Hasil sinkronisasi
- Objek
SyncResult
yang Anda gunakan untuk mengirim informasi ke framework adaptor sinkronisasi.
Cuplikan berikut menunjukkan keseluruhan struktur
onPerformSync()
:
Kotlin
/* * Specify the code you want to run in the sync adapter. The entire * sync adapter runs in a background thread, so you don't have to set * up your own background processing. */ override fun onPerformSync( account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult ) { /* * Put the data transfer code here. */ }
Java
/* * Specify the code you want to run in the sync adapter. The entire * sync adapter runs in a background thread, so you don't have to set * up your own background processing. */ @Override public void onPerformSync( Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { /* * Put the data transfer code here. */ }
Meskipun penerapan aktual
onPerformSync()
dikhususkan untuk
persyaratan sinkronisasi data aplikasi dan protokol koneksi server, ada beberapa
tugas umum yang harus dilakukan oleh penerapan Anda:
- Menghubungkan ke server
- Meskipun Anda dapat berasumsi bahwa jaringan tersedia saat transfer data dimulai, framework adaptor sinkronisasi tidak akan terhubung secara otomatis ke server.
- Mendownload dan mengupload data
- Adaptor sinkronisasi tidak mengotomatiskan tugas transfer data apa pun. Jika ingin mendownload data dari server dan menyimpannya di penyedia konten, Anda harus memberikan kode yang meminta data tersebut, mendownloadnya, dan memasukkannya dalam penyedia. Demikian pula, jika ingin mengirim data ke server, Anda harus membacanya dari file, database, atau penyedia, dan mengirim permintaan upload yang diperlukan. Anda juga harus menangani error jaringan yang terjadi saat transfer data berjalan.
- Menangani konflik data atau menentukan status data
- Adaptor sinkronisasi tidak otomatis menangani konflik antara data di server dan data di perangkat. Selain itu, DNS tidak otomatis mendeteksi apakah data di server lebih baru daripada data di perangkat, atau sebaliknya. Sebagai gantinya, Anda harus menyediakan algoritma sendiri untuk menangani situasi ini.
- Pembersihan.
- Selalu tutup koneksi ke server serta bersihkan file sementara dan cache di akhir transfer data Anda.
Catatan: Framework adaptor sinkronisasi menjalankan onPerformSync()
di thread latar belakang, sehingga Anda tidak perlu menyiapkan pemrosesan latar belakang sendiri.
Selain tugas yang berhubungan dengan sinkronisasi, Anda juga harus mencoba menggabungkan tugas terkait jaringan reguler Anda dan menambahkannya ke onPerformSync()
.
Dengan memusatkan semua tugas jaringan Anda dalam metode ini, Anda dapat menghemat daya baterai yang
diperlukan untuk memulai dan menghentikan antarmuka jaringan. Untuk mempelajari lebih lanjut cara membuat akses jaringan menjadi lebih efisien, lihat kelas pelatihan Mentransfer Data Tanpa Menguras Baterai, yang menjelaskan beberapa tugas akses jaringan yang dapat Anda sertakan dalam kode transfer data.
Mengaitkan adaptor sinkronisasi ke framework
Sekarang Anda memiliki kode transfer data yang dienkapsulasi dalam komponen adaptor sinkronisasi, tetapi Anda harus memberi framework akses ke kode Anda. Untuk melakukannya, Anda harus membuat Service
terikat yang meneruskan objek binder Android khusus dari komponen adaptor sinkronisasi ke framework. Dengan objek binder ini, framework dapat memanggil
metode onPerformSync()
dan
meneruskan data ke dalamnya.
Buat instance komponen adaptor sinkronisasi sebagai singleton pada metode onCreate()
layanan. Dengan membuat instance
komponen di onCreate()
, Anda akan menunda
pembuatannya hingga layanan dimulai, yang terjadi saat framework mencoba menjalankan
transfer data Anda untuk pertama kalinya. Anda harus membuat instance komponen dengan cara yang aman untuk thread, jika framework adaptor sinkronisasi mengantrekan beberapa eksekusi adaptor sinkronisasi Anda sebagai respons terhadap pemicu atau penjadwalan.
Misalnya, cuplikan berikut menunjukkan cara membuat class yang menerapkan Service
terikat, membuat instance komponen adaptor sinkronisasi, dan mendapatkan objek binder Android:
Kotlin
package com.example.android.syncadapter /** * Define a Service that returns an [android.os.IBinder] for the * sync adapter class, allowing the sync adapter framework to call * onPerformSync(). */ class SyncService : Service() { /* * Instantiate the sync adapter object. */ override fun onCreate() { /* * Create the sync adapter as a singleton. * Set the sync adapter as syncable * Disallow parallel syncs */ synchronized(sSyncAdapterLock) { sSyncAdapter = sSyncAdapter ?: SyncAdapter(applicationContext, true) } } /** * Return an object that allows the system to invoke * the sync adapter. * */ override fun onBind(intent: Intent): IBinder { /* * Get the object that allows external processes * to call onPerformSync(). The object is created * in the base class code when the SyncAdapter * constructors call super() * * We should never be in a position where this is called before * onCreate() so the exception should never be thrown */ return sSyncAdapter?.syncAdapterBinder ?: throw IllegalStateException() } companion object { // Storage for an instance of the sync adapter private var sSyncAdapter: SyncAdapter? = null // Object to use as a thread-safe lock private val sSyncAdapterLock = Any() } }
Java
package com.example.android.syncadapter; /** * Define a Service that returns an <code><a href="/reference/android/os/IBinder.html">IBinder</a></code> for the * sync adapter class, allowing the sync adapter framework to call * onPerformSync(). */ public class SyncService extends Service { // Storage for an instance of the sync adapter private static SyncAdapter sSyncAdapter = null; // Object to use as a thread-safe lock private static final Object sSyncAdapterLock = new Object(); /* * Instantiate the sync adapter object. */ @Override public void onCreate() { /* * Create the sync adapter as a singleton. * Set the sync adapter as syncable * Disallow parallel syncs */ synchronized (sSyncAdapterLock) { if (sSyncAdapter == null) { sSyncAdapter = new SyncAdapter(getApplicationContext(), true); } } } /** * Return an object that allows the system to invoke * the sync adapter. * */ @Override public IBinder onBind(Intent intent) { /* * Get the object that allows external processes * to call onPerformSync(). The object is created * in the base class code when the SyncAdapter * constructors call super() */ return sSyncAdapter.getSyncAdapterBinder(); } }
Catatan: Untuk melihat contoh layanan terikat yang lebih detail untuk adaptor sinkronisasi, lihat contoh aplikasi.
Menambahkan akun yang diperlukan oleh framework
Framework adaptor sinkronisasi mengharuskan setiap adaptor sinkronisasi memiliki jenis akun. Anda mendeklarasikan nilai jenis akun di bagian Menambahkan File Metadata Authenticator. Sekarang, Anda harus menyiapkan jenis akun ini di
sistem Android. Untuk menyiapkan jenis akun, tambahkan akun placeholder yang menggunakan jenis akun tersebut
dengan memanggil addAccountExplicitly()
.
Tempat terbaik untuk memanggil metode ini adalah metode onCreate()
dari aktivitas pembuka aplikasi Anda. Cuplikan kode berikut menunjukkan cara melakukan hal ini:
Kotlin
... // Constants // The authority for the sync adapter's content provider const val AUTHORITY = "com.example.android.datasync.provider" // An account type, in the form of a domain name const val ACCOUNT_TYPE = "example.com" // The account name const val ACCOUNT = "placeholderaccount" ... class MainActivity : FragmentActivity() { // Instance fields private lateinit var mAccount: Account ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... // Create the placeholder account mAccount = createSyncAccount() ... } ... /** * Create a new placeholder account for the sync adapter */ private fun createSyncAccount(): Account { val accountManager = getSystemService(Context.ACCOUNT_SERVICE) as AccountManager return Account(ACCOUNT, ACCOUNT_TYPE).also { newAccount -> /* * Add the account and account type, no password or user data * If successful, return the Account object, otherwise report an error. */ if (accountManager.addAccountExplicitly(newAccount, null, null)) { /* * If you don't set android:syncable="true" in * in your <provider> element in the manifest, * then call context.setIsSyncable(account, AUTHORITY, 1) * here. */ } else { /* * The account exists or some other error occurred. Log this, report it, * or handle it internally. */ } } } ... }
Java
public class MainActivity extends FragmentActivity { ... ... // Constants // The authority for the sync adapter's content provider public static final String AUTHORITY = "com.example.android.datasync.provider"; // An account type, in the form of a domain name public static final String ACCOUNT_TYPE = "example.com"; // The account name public static final String ACCOUNT = "placeholderaccount"; // Instance fields Account mAccount; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Create the placeholder account mAccount = CreateSyncAccount(this); ... } ... /** * Create a new placeholder account for the sync adapter * * @param context The application context */ public static Account CreateSyncAccount(Context context) { // Create the account type and default account Account newAccount = new Account( ACCOUNT, ACCOUNT_TYPE); // Get an instance of the Android account manager AccountManager accountManager = (AccountManager) context.getSystemService( ACCOUNT_SERVICE); /* * Add the account and account type, no password or user data * If successful, return the Account object, otherwise report an error. */ if (accountManager.addAccountExplicitly(newAccount, null, null)) { /* * If you don't set android:syncable="true" in * in your <provider> element in the manifest, * then call context.setIsSyncable(account, AUTHORITY, 1) * here. */ } else { /* * The account exists or some other error occurred. Log this, report it, * or handle it internally. */ } } ... }
Menambahkan file metadata adaptor sinkronisasi
Untuk mencolokkan komponen adaptor sinkronisasi ke dalam framework, Anda harus menyediakan framework dengan metadata yang menjelaskan komponen dan memberikan tanda tambahan. Metadata tersebut menentukan jenis akun yang Anda buat untuk adaptor sinkronisasi, mendeklarasikan otoritas penyedia konten yang terkait dengan aplikasi Anda, mengontrol bagian antarmuka pengguna sistem yang terkait dengan adaptor sinkronisasi, dan mendeklarasikan tanda lainnya yang terkait dengan sinkronisasi. Deklarasikan metadata ini dalam file XML khusus yang disimpan di
direktori /res/xml/
dalam project aplikasi Anda. Anda dapat memberi nama apa pun ke file, meskipun biasanya disebut syncadapter.xml
.
File XML ini berisi satu elemen XML <sync-adapter>
yang memiliki
atribut berikut:
android:contentAuthority
-
Otoritas URI untuk penyedia konten Anda. Jika Anda membuat penyedia konten stub untuk
aplikasi di tutorial Membuat Penyedia Konten Stub sebelumnya, gunakan nilai yang Anda tentukan untuk
atribut
android:authorities
dalam elemen<provider>
yang ditambahkan ke manifes aplikasi Anda. Atribut ini dijelaskan secara lebih detail di bagian Mendeklarasikan Penyedia dalam Manifes.
Jika Anda mentransfer data dari penyedia konten ke server dengan adaptor sinkronisasi, nilai ini harus sama dengan otoritas URI konten yang Anda gunakan untuk data tersebut. Nilai ini juga merupakan salah satu otoritas yang Anda tetapkan dalam atributandroid:authorities
dari elemen<provider>
yang mendeklarasikan penyedia dalam manifes aplikasi. android:accountType
-
Jenis akun yang diperlukan oleh framework adaptor sinkronisasi. Nilai harus sama dengan nilai jenis akun yang Anda berikan saat membuat file metadata pengautentikasi, seperti yang dijelaskan di bagian Menambahkan File Metadata Authenticator. Ini juga merupakan nilai yang Anda tentukan untuk
konstanta
ACCOUNT_TYPE
dalam cuplikan kode di bagian Menambahkan Akun yang Diperlukan oleh Framework. - Atribut setelan
-
-
android:userVisible
- Menetapkan visibilitas jenis akun adaptor sinkronisasi. Secara default, ikon dan label akun yang terkait dengan jenis akun terlihat di bagian Akun pada aplikasi Setelan sistem, jadi Anda harus membuat adaptor sinkronisasi tidak terlihat, kecuali Anda memiliki jenis akun atau domain yang mudah dikaitkan dengan aplikasi Anda. Jika Anda tidak menampilkan jenis akun, Anda masih dapat mengizinkan pengguna untuk mengontrol adaptor sinkronisasi dengan antarmuka pengguna di salah satu aktivitas aplikasi Anda.
-
android:supportsUploading
-
Memungkinkan Anda mengupload data ke cloud. Tetapkan nilainya ke
false
jika aplikasi Anda hanya mendownload data. -
android:allowParallelSyncs
- Memungkinkan beberapa instance komponen adaptor sinkronisasi dijalankan di waktu yang sama. Gunakan metode ini jika aplikasi mendukung beberapa akun pengguna dan Anda ingin mengizinkan beberapa pengguna mentransfer data secara paralel. Flag ini tidak berpengaruh jika Anda tidak pernah menjalankan transfer data multipel.
-
android:isAlwaysSyncable
-
Menunjukkan kepada framework adaptor sinkronisasi bahwa framework tersebut dapat menjalankan adaptor sinkronisasi kapan pun
yang Anda tentukan. Jika Anda ingin mengontrol waktu adaptor sinkronisasi berjalan secara terprogram, tetapkan flag ini ke
false
, lalu panggilrequestSync()
untuk menjalankan adaptor sinkronisasi. Untuk mempelajari lebih lanjut cara menjalankan adaptor sinkronisasi, lihat tutorial Menjalankan Adaptor Sinkronisasi
-
Contoh berikut menunjukkan XML untuk adaptor sinkronisasi yang menggunakan satu akun placeholder dan hanya melakukan download.
<?xml version="1.0" encoding="utf-8"?> <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.example.android.datasync.provider" android:accountType="com.android.example.datasync" android:userVisible="false" android:supportsUploading="false" android:allowParallelSyncs="false" android:isAlwaysSyncable="true"/>
Mendeklarasikan adaptor sinkronisasi dalam manifes
Setelah menambahkan komponen adaptor sinkronisasi ke aplikasi, Anda harus meminta izin terkait penggunaan komponen tersebut, dan harus mendeklarasikan Service
terikat yang telah ditambahkan.
Karena komponen adaptor sinkronisasi menjalankan kode yang mentransfer data antara jaringan dan perangkat, Anda perlu meminta izin untuk mengakses Internet. Selain itu, aplikasi Anda perlu meminta izin untuk membaca dan menulis setelan adaptor sinkronisasi, sehingga Anda dapat mengontrol adaptor sinkronisasi secara terprogram dari komponen lain di aplikasi Anda. Anda juga perlu meminta izin khusus yang memungkinkan aplikasi Anda menggunakan komponen pengautentikasi yang Anda buat dalam tutorial Membuat Authenticator Stub.
Untuk meminta izin ini, tambahkan hal berikut ke manifes aplikasi Anda sebagai elemen turunan <manifest>
:
-
android.permission.INTERNET
- Memungkinkan kode adaptor sinkronisasi mengakses Internet sehingga dapat mendownload atau mengupload data dari perangkat ke server. Anda tidak perlu menambahkan izin ini lagi jika telah memintanya sebelumnya.
-
android.permission.READ_SYNC_SETTINGS
-
Mengizinkan aplikasi Anda membaca setelan adaptor sinkronisasi saat ini. Misalnya, Anda memerlukan izin ini untuk memanggil
getIsSyncable()
. -
android.permission.WRITE_SYNC_SETTINGS
-
Memungkinkan aplikasi Anda mengontrol setelan adaptor sinkronisasi. Anda memerlukan izin ini untuk menyetel adaptor sinkronisasi berkala yang berjalan menggunakan
addPeriodicSync()
. Izin ini tidak diperlukan untuk memanggilrequestSync()
. Untuk mempelajari lebih lanjut cara menjalankan adaptor sinkronisasi, lihat Menjalankan Adaptor Sinkronisasi.
Cuplikan berikut menunjukkan cara menambahkan izin:
<manifest> ... <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/> ... </manifest>
Terakhir, untuk mendeklarasikan Service
terikat yang digunakan framework untuk berinteraksi dengan adaptor sinkronisasi, tambahkan XML berikut ke manifes aplikasi Anda sebagai elemen turunan <application>
:
<service android:name="com.example.android.datasync.SyncService" android:exported="false" android:process=":sync"> <intent-filter> <action android:name="android.content.SyncAdapter"/> </intent-filter> <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" /> </service>
Elemen
<intent-filter>
menyiapkan filter yang dipicu oleh tindakan intent
android.content.SyncAdapter
, yang dikirim oleh sistem untuk menjalankan adaptor sinkronisasi. Saat filter
dipicu, sistem akan memulai layanan terikat yang Anda buat, dalam contoh ini adalah
SyncService
. Atribut
android:exported="false"
hanya memungkinkan aplikasi Anda dan sistem untuk mengakses
Service
. Atribut
android:process=":sync"
memberi tahu sistem untuk menjalankan Service
dalam proses bersama global bernama
sync
. Jika Anda memiliki beberapa adaptor sinkronisasi di aplikasi, adaptor tersebut dapat berbagi proses ini,
yang akan mengurangi overhead.
Elemen
<meta-data>
menyediakan nama file XML metadata adaptor sinkronisasi yang Anda buat sebelumnya.
Atribut
android:name
menunjukkan bahwa metadata ini ditujukan untuk framework adaptor sinkronisasi. Elemen
android:resource
menentukan nama file metadata.
Sekarang Anda memiliki semua komponen untuk adaptor sinkronisasi Anda. Tutorial berikutnya akan menunjukkan cara memberi tahu framework adaptor sinkronisasi untuk menjalankan adaptor sinkronisasi, baik sebagai respons terhadap suatu peristiwa maupun pada jadwal rutin.