Nota: consigliamo WorkManager consigliata per la maggior parte dei casi d'uso relativi all'elaborazione in background. Fai riferimento alle guida all'elaborazione in background per scoprire quale soluzione funziona meglio per te.
Il componente dell'adattatore di sincronizzazione nella tua app contiene il codice per le attività che trasferiscono i dati tra il dispositivo e un server. In base alla pianificazione e agli attivatori che fornisci in nell'app, il framework dell'adattatore di sincronizzazione esegue il codice nel componente dell'adattatore di sincronizzazione. Per aggiungere un di sincronizzazione dell'adattatore alla tua app, devi aggiungere quanto segue:
- Classe adattatore di sincronizzazione.
- Una classe che aggrega il codice Data Transfer in un'interfaccia compatibile con l'adattatore di sincronizzazione. il modello di machine learning.
-
Associato
Service
. - Un componente che consente al framework dell'adattatore di sincronizzazione di eseguire il codice nell'adattatore di sincronizzazione .
- File XML dei metadati dell'adattatore di sincronizzazione.
- Un file contenente informazioni sull'adattatore di sincronizzazione. Il framework legge questo file scopri come caricare e pianificare il trasferimento dei dati.
- Dichiarazioni nel file manifest dell'app.
- XML che dichiara il servizio associato e punta a sincronizzare i metadati specifici dell'adattatore.
Questa lezione mostra come definire questi elementi.
Crea una classe dell'adattatore di sincronizzazione
In questa parte della lezione imparerai a creare la classe dell'adattatore di sincronizzazione che incapsula il codice di trasferimento dati. La creazione della classe include l'estensione della classe base dell'adattatore di sincronizzazione, la definizione costruttori per la classe e implementando il metodo in cui definisci il trasferimento attività di machine learning.
Estendi la classe dell'adattatore di sincronizzazione di base
Per creare il componente dell'adattatore di sincronizzazione, inizia estendendo
AbstractThreadedSyncAdapter
e scrivere i relativi costruttori. Utilizza la
per eseguire attività di configurazione ogni volta che viene creato il componente dell'adattatore di sincronizzazione
da zero, proprio come usi Activity.onCreate()
per configurare
attività. Ad esempio, se la tua app usa un fornitore di contenuti per archiviare i dati, utilizza i costruttori
per ottenere un'istanza ContentResolver
. Poiché una seconda forma
è stato aggiunto nella piattaforma Android versione 3.0 per supportare parallelSyncs
devi creare due forme del costruttore per mantenere la compatibilità.
Nota:la struttura dell'adattatore di sincronizzazione è progettata per funzionare con l'adattatore di sincronizzazione. che sono istanze singleton. La creazione dell'istanza del componente dell'adattatore di sincronizzazione è trattata in modo più dettagliato nella sezione Vincola l'adattatore di sincronizzazione al framework.
L'esempio seguente mostra come implementare
AbstractThreadedSyncAdapter
e i relativi costruttori:
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(); ... }
Aggiungi il codice di trasferimento di dati
Il componente dell'adattatore di sincronizzazione non esegue automaticamente il trasferimento dei dati. Invece,
incapsula il codice di trasferimento dei dati, in modo che il framework dell'adattatore di sincronizzazione possa eseguire
trasferimento di dati in background, senza il coinvolgimento dell'app. Quando il framework è pronto
per sincronizzare i dati dell'applicazione, richiama l'implementazione del metodo
onPerformSync()
.
Per facilitare il trasferimento dei dati dal codice principale dell'app al componente dell'adattatore di sincronizzazione,
il framework dell'adattatore di sincronizzazione
onPerformSync()
con
i seguenti argomenti:
- Account
-
Un oggetto
Account
associato all'evento che ha attivato l'elemento l'adattatore di sincronizzazione. Se il tuo server non utilizza account, non è necessario utilizzare informazioni in questo oggetto. - Extra
-
Un elemento
Bundle
contenente i flag inviati dall'evento che ha attivato la sincronizzazione dell'adattatore. - Competenza
- L'autorità di un fornitore di contenuti nel sistema. L'app deve avere accesso a questo fornitore. In genere, l'autorità corrisponde a un fornitore di contenuti nella tua app. di Gemini Advanced.
- Client fornitore di contenuti
-
Il
ContentProviderClient
per il fornitore di contenuti indicato dal l'argomento dell'autorità di certificazione. UnContentProviderClient
è un pubblico leggero a un fornitore di contenuti. Ha le stesse funzionalità di base di unContentResolver
. Se utilizzi un fornitore di contenuti per archiviare i dati per la tua app, puoi connetterti al provider utilizzando questo oggetto. Altrimenti, puoi ignorare li annotino. - Risultato della sincronizzazione
-
Un oggetto
SyncResult
che utilizzi per inviare informazioni alla sincronizzazione framework dell'adattatore.
Lo snippet seguente mostra la struttura generale
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. */ }
Sebbene l'implementazione effettiva
onPerformSync()
è specifico per
i requisiti per la sincronizzazione dei dati e i protocolli di connessione
al server dell'app, esistono alcune
attività generali che l'implementazione dovrebbe eseguire:
- Connessione a un server
- Anche se si può presumere che la rete sia disponibile all'inizio del trasferimento di dati, framework adattatori di sincronizzazione non si connette automaticamente a un server.
- Download e caricamento dei dati
- L'adattatore di sincronizzazione non automatizza le attività di trasferimento dei dati. Se vuoi scaricare dati da un server e li archivia in un fornitore di contenuti, devi fornire il codice richiede i dati, li scarica e li inserisce nel provider. Analogamente, se vuoi i dati a un server, devi leggerli da un file, un database o un provider e inviare la richiesta di caricamento necessaria. Devi anche gestire gli errori di rete che si verificano Data Transfer è in esecuzione.
- Gestione dei conflitti di dati o determinazione del livello di attualità dei dati
- Un adattatore di sincronizzazione non gestisce automaticamente i conflitti tra i dati sul server e i dati sul dispositivo. Inoltre, non rileva automaticamente se i dati sul server sono più recenti di i dati sul dispositivo o viceversa. ma devi fornire i tuoi algoritmi per gestire questa situazione.
- Esegui la pulizia.
- Chiudi sempre le connessioni a un server e pulisci i file temporanei e le cache alla fine il trasferimento dei dati.
Nota: il framework dell'adattatore di sincronizzazione viene eseguito
onPerformSync()
su
thread in background, evitando così di dover configurare un'elaborazione in background personalizzata.
Oltre alle attività relative alla sincronizzazione, dovresti provare a combinare le tue normali
relative alla rete e aggiungerle
onPerformSync()
.
Concentrando tutte le attività di rete in questo metodo, risparmierai la carica della batteria
necessarie per avviare e arrestare le interfacce di rete. Per scoprire di più su come migliorare l'accesso alla rete
efficiente, consulta il corso Trasferimento di dati senza scaricare la batteria, in cui sono descritti diversi metodi di accesso
che puoi includere nel codice di Data Transfer.
Associa l'adattatore di sincronizzazione al framework
Il codice di trasferimento dei dati è ora incapsulato in un componente dell'adattatore di sincronizzazione, ma
per fornire al framework l'accesso al codice. Per farlo, devi creare un limite
Service
che trasmette un oggetto binder Android speciale dall'adattatore di sincronizzazione
al framework. Con questo oggetto binder, il framework può richiamare il metodo
onPerformSync()
e
passare dati al progetto.
Crea un'istanza del componente dell'adattatore di sincronizzazione come singleton nella
onCreate()
del servizio. Creando un'istanza
il componente in onCreate()
, rinviare
creandolo fino all'avvio del servizio, cosa che accade quando il framework tenta per la prima volta di eseguire
trasferimento di dati. Devi creare un'istanza del componente in modo sicuro per thread, nel caso in cui venga eseguita la sincronizzazione
del framework dell'adattatore mette in coda più esecuzioni dell'adattatore di sincronizzazione in risposta ai trigger
pianificazione.
Ad esempio, il seguente snippet mostra come creare una classe che implementa la funzione
associato Service
, crea un'istanza del componente adattatore di sincronizzazione e ottiene
Oggetto 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(); } }
Nota:per vedere un esempio più dettagliato di un servizio associato per un adattatore di sincronizzazione, guarda l'app di esempio.
Aggiungi l'account richiesto dal framework
Il framework dell'adattatore di sincronizzazione richiede che ogni adattatore di sincronizzazione abbia un tipo di account. Hai dichiarato
il valore del tipo di account nella sezione
Aggiungi il file di metadati di Authenticator. Ora devi configurare questo tipo di account nel
Sistema Android. Per configurare il tipo di account, aggiungi un account segnaposto che utilizzi il tipo di account
chiamando il numero addAccountExplicitly()
.
Il modo migliore per chiamare il metodo è
onCreate()
metodo della tua app
attività di apertura. Il seguente snippet di codice mostra come eseguire questa operazione:
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. */ } } ... }
Aggiungi il file dei metadati dell'adattatore di sincronizzazione
Per collegare il componente dell'adattatore di sincronizzazione al framework, devi fornire il framework
con metadati che descrivono il componente e forniscono ulteriori flag. I metadati specificano
il tipo di account che hai creato per l'adattatore di sincronizzazione, dichiara un'autorità del fornitore di contenuti
associati alla tua app, controlla una parte dell'interfaccia utente di sistema relativa agli adattatori di sincronizzazione,
e dichiara altri flag relativi alla sincronizzazione. Dichiara questi metadati in un file XML speciale archiviato in
nella directory /res/xml/
nel progetto dell'app. Puoi assegnare qualsiasi nome al file,
anche se di solito si chiama syncadapter.xml
.
Questo file XML contiene un singolo elemento XML <sync-adapter>
con
i seguenti attributi:
android:contentAuthority
-
L'autorità URI del tuo fornitore di contenuti. Se è stato creato un fornitore di contenuti stub per
nella lezione precedente Creare un fornitore di contenuti Stub, utilizza il valore specificato per
attributo
android:authorities
nell'elemento<provider>
che hai aggiunto al file manifest dell'app. Questo attributo è descritti più dettagliatamente nella sezione Dichiara il fornitore nel manifest.
Se trasferisci i dati da un fornitore di contenuti a un server con l'adattatore di sincronizzazione, deve corrispondere all'autorità per l'URI dei contenuti utilizzata per i dati. Questo valore è anche una delle autorità da te specificate nelandroid:authorities
dell'elemento<provider>
che dichiara il tuo fornitore nel file manifest dell'app. android:accountType
-
Il tipo di account richiesto dal framework dell'adattatore di sincronizzazione. Il valore deve essere lo stesso
come valore del tipo di account che hai fornito al momento della creazione del file dei metadati dell'autenticatore,
descritto nella sezione Aggiungere il file di metadati di Authenticator. È anche il valore specificato per l'attributo
costante
ACCOUNT_TYPE
nello snippet di codice nella sezione Aggiungere l'account richiesto dal framework. - Attributi delle impostazioni
-
-
android:userVisible
- Consente di impostare la visibilità del tipo di account dell'adattatore di sincronizzazione. Per impostazione predefinita, l'icona e l'etichetta dell'account associate al tipo di account sono visibili nella Account dell'app Impostazioni del sistema, quindi dovresti effettuare la sincronizzazione adattatore invisibile a meno che tu non abbia un tipo di account o un dominio facilmente associabile con la tua app. Se rendi invisibile il tuo tipo di account, puoi comunque consentire agli utenti di controlla l'adattatore di sincronizzazione con un'interfaccia utente in una delle attività dell'app.
-
android:supportsUploading
-
Ti permette di caricare i dati sul cloud. Imposta questo elemento su
false
solo se la tua app scarica i dati. -
android:allowParallelSyncs
- Consente di eseguire contemporaneamente più istanze del componente dell'adattatore di sincronizzazione. Utilizza questa opzione se la tua app supporta più account utente e vuoi consentire agli utenti di trasferire i dati in parallelo. Questo flag non ha effetto se non esegui mai più trasferimenti di dati.
-
android:isAlwaysSyncable
-
Indica al framework dell'adattatore di sincronizzazione che può eseguire l'adattatore di sincronizzazione in qualsiasi
all'ora specificata. Se vuoi controllare in modo programmatico quando la sincronizzazione
l'adattatore può essere eseguito, imposta questo flag su
false
e richiamarequestSync()
per eseguire l'adattatore di sincronizzazione. Per ulteriori informazioni sull'esecuzione di un adattatore di sincronizzazione, consulta la Eseguire un adattatore di sincronizzazione
-
L'esempio seguente mostra l'XML per un adattatore di sincronizzazione che utilizza un singolo account segnaposto e esegue solo 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"/>
Dichiara l'adattatore di sincronizzazione nel file manifest
Dopo aver aggiunto il componente adattatore di sincronizzazione all'app, devi richiedere le autorizzazioni
relative all'utilizzo del componente e devi dichiarare il vincolo Service
che hai aggiunto.
Poiché il componente dell'adattatore di sincronizzazione esegue un codice che trasferisce i dati tra la rete e dispositivo, devi richiedere l'autorizzazione ad accedere a internet. Inoltre, la tua app deve per richiedere l'autorizzazione a leggere e scrivere le impostazioni dell'adattatore di sincronizzazione, così puoi controllare la sincronizzazione a livello di programmazione da altri componenti della tua app. Devi inoltre richiedere autorizzazione speciale che consente alla tua app di usare il componente di autenticazione che hai creato nella lezione Creazione di un'autenticatore Stub.
Per richiedere queste autorizzazioni, aggiungi quanto segue al file manifest dell'app come elementi secondari di
<manifest>
:
-
android.permission.INTERNET
- Consente al codice dell'adattatore di sincronizzazione di accedere a Internet per scaricare o caricare dati dal dispositivo a un server. Non è necessario aggiungere di nuovo questa autorizzazione se in precedenza.
-
android.permission.READ_SYNC_SETTINGS
-
Consente all'app di leggere le impostazioni correnti dell'adattatore di sincronizzazione. Ad esempio, ti serve questo
l'autorizzazione per chiamare
getIsSyncable()
. -
android.permission.WRITE_SYNC_SETTINGS
-
Consente all'app di controllare le impostazioni dell'adattatore di sincronizzazione. Devi disporre di questa autorizzazione per poter
imposta le esecuzioni dell'adattatore di sincronizzazione periodica utilizzando
addPeriodicSync()
. Questa autorizzazione non è necessaria per chiamarerequestSync()
. Per scoprire di più su che utilizza l'adattatore di sincronizzazione, consulta Esecuzione di un adattatore di sincronizzazione.
Lo snippet seguente mostra come aggiungere le autorizzazioni:
<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>
Infine, per dichiarare il valore Service
associato che il framework utilizza per
interagisci con l'adattatore di sincronizzazione, aggiungi il seguente XML al file manifest dell'app come elemento secondario
di <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>
La
<intent-filter>
configura un filtro che viene attivato dall'azione di intent
android.content.SyncAdapter
, inviato dal sistema per eseguire l'adattatore di sincronizzazione. Quando il filtro
, il sistema avvia il servizio associato che hai creato, che in questo esempio
SyncService
. L'attributo
android:exported="false"
consente solo alla tua app e al sistema di accedere
Service
. L'attributo
android:process=":sync"
indica al sistema di eseguire Service
in un processo condiviso globale denominato
sync
. Se nella tua app sono presenti più adattatori di sincronizzazione, gli utenti possono condividere questo processo,
con conseguente riduzione dei costi generali.
La
<meta-data>
fornisce il nome del file XML dei metadati dell'adattatore di sincronizzazione che hai creato in precedenza.
La
android:name
indica che questi metadati riguardano il framework dell'adattatore di sincronizzazione. La
android:resource
specifica il nome del file di metadati.
Ora hai tutti i componenti dell'adattatore di sincronizzazione. La prossima lezione ti mostrerà come indica al framework dell'adattatore di sincronizzazione di eseguire l'adattatore di sincronizzazione, in risposta a un evento o il giorno con una programmazione regolare.