Remarque:Nous vous recommandons d'utiliser WorkManager. est recommandée pour la plupart des cas d'utilisation du traitement en arrière-plan. Pour plus d'informations, veuillez consulter le guide de traitement en arrière-plan pour identifier la solution la mieux adaptée à vos besoins.
Le composant d'adaptateur de synchronisation de votre application encapsule le code pour les tâches transférées entre l'appareil et un serveur. En fonction de la planification et des déclencheurs que vous indiquez dans votre application, le framework d'adaptateur de synchronisation exécute le code du composant d'adaptateur de synchronisation. Pour ajouter un composant adaptateur de synchronisation à votre application, vous devez ajouter les éléments suivants:
- Classe d'adaptateur de synchronisation.
- Une classe qui encapsule votre code de transfert de données dans une interface compatible avec l'adaptateur de synchronisation. d'infrastructure.
-
Service
lié. - Composant permettant au framework d'adaptateur de synchronisation d'exécuter le code de votre adaptateur de synchronisation. .
- Fichier de métadonnées XML de l'adaptateur de synchronisation.
- Fichier contenant des informations sur votre adaptateur de synchronisation. Le framework lit ce fichier découvrez comment charger et planifier votre transfert de données.
- Déclarations dans le fichier manifeste de l'application
- Fichier XML qui déclare le service lié et pointe vers les métadonnées spécifiques à l'adaptateur.
Cette leçon vous explique comment définir ces éléments.
Créer une classe d'adaptateur de synchronisation
Dans cette partie de la leçon, vous allez apprendre à créer la classe d'adaptateur de synchronisation qui encapsule l'objet code de transfert de données. La création de la classe inclut l'extension de la classe de base de l'adaptateur de synchronisation, la définition constructeurs pour la classe et implémenter la méthode permettant de définir le transfert de données tâches.
Étendre la classe de l'adaptateur de synchronisation de base
Pour créer le composant d'adaptateur de synchronisation, commencez par étendre
AbstractThreadedSyncAdapter
et l'écriture de ses constructeurs. Utilisez les
constructeurs pour exécuter des tâches de configuration chaque fois que votre composant d'adaptateur de synchronisation est créé à partir de
de la même manière que vous utilisez Activity.onCreate()
pour configurer
activité. Par exemple, si votre application utilise un fournisseur de contenu pour stocker des données, utilisez les constructeurs
pour obtenir une instance ContentResolver
. Puisqu'une deuxième forme
du constructeur a été ajouté à la version 3.0 de la plate-forme Android pour prendre en charge parallelSyncs
vous devez créer deux formes du constructeur pour maintenir la compatibilité.
Remarque:Le framework d'adaptateur de synchronisation est conçu pour fonctionner avec l'adaptateur de synchronisation. qui sont des instances singleton. Nous allons voir comment instancier le composant de l'adaptateur de synchronisation. dans la section Associez l'adaptateur de synchronisation au framework.
L'exemple suivant vous montre comment implémenter
AbstractThreadedSyncAdapter
et ses constructeurs:
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(); ... }
Ajouter le code de transfert de données
Le composant d'adaptateur de synchronisation n'effectue pas automatiquement le transfert de données. Au lieu de cela, il
encapsule votre code de transfert de données, de sorte que le framework de l'adaptateur de synchronisation puisse exécuter la
transfert de données en arrière-plan, sans intervention de votre application. Lorsque le framework est prêt
pour synchroniser les données de votre application, l'implémentation de la méthode
onPerformSync()
Pour faciliter le transfert des données du code de votre application principale vers le composant de l'adaptateur de synchronisation,
le framework de l'adaptateur de synchronisation appelle
onPerformSync()
avec le
les arguments suivants:
- Compte
-
Un objet
Account
associé à l'événement qui a déclenché l'adaptateur de synchronisation. Si votre serveur n'utilise pas de comptes, vous n'avez pas besoin d'utiliser la dans cet objet. - Bonus
-
Bundle
contenant les indicateurs envoyés par l'événement ayant déclenché la synchronisation. adaptateur secteur. - Autorité
- L'autorité d'un fournisseur de contenu dans le système. Votre application doit avoir accès à ce fournisseur. En général, l'autorité correspond à un fournisseur de contenu dans votre propre application.
- Client du fournisseur de contenu
-
ContentProviderClient
pour le fournisseur de contenu vers lequel l'élément l'argument "authority". UnContentProviderClient
est un fichier public léger à un fournisseur de contenu. Il offre les mêmes fonctionnalités de base qu'unContentResolver
Si vous utilisez un fournisseur de contenu pour stocker des données pour votre application, vous pouvez vous connecter au fournisseur avec cet objet. Sinon, vous pouvez ignorer - Résultat de la synchronisation
-
Un objet
SyncResult
que vous utilisez pour envoyer des informations à la synchronisation un framework d'adaptateurs.
L'extrait de code suivant montre la structure globale
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. */ }
Bien que l'implémentation réelle
onPerformSync()
est spécifique à
les exigences de synchronisation des données et les protocoles de connexion au serveur de votre application,
tâches générales que votre implémentation doit effectuer:
- Connexion à un serveur
- Bien que vous puissiez partir du principe que le réseau est disponible au début du transfert de données, l'infrastructure d'adaptateur de synchronisation ne se connecte pas automatiquement à un serveur.
- Télécharger et importer des données
- Un adaptateur de synchronisation n'automatise pas les tâches de transfert de données. Si vous voulez télécharger d'un serveur et les stocker chez un fournisseur de contenu, vous devez fournir le code demande les données, les télécharge et les insère dans le fournisseur. De même, si vous souhaitez envoyer des données à un serveur, vous devez les lire à partir d'un fichier, d'une base de données ou d'un fournisseur, la demande d'importation nécessaire. Vous devez également gérer les erreurs réseau qui se produisent le transfert de données est en cours.
- Gérer les conflits de données ou déterminer l'actualité des données
- Un adaptateur de synchronisation ne gère pas automatiquement les conflits entre les données sur le serveur et celles sur l'appareil. De plus, il ne détecte pas automatiquement si les données présentes sur le serveur sont plus récentes que des données sur l'appareil, ou inversement. Vous devez fournir vos propres algorithmes gérer cette situation.
- Effectuer un nettoyage.
- Fermez toujours les connexions à un serveur et nettoyez les fichiers temporaires et les caches à la fin de votre transfert de données.
Remarque:Le framework d'adaptateur de synchronisation s'exécute
onPerformSync()
sur un
ce qui vous évite d'avoir à configurer votre propre traitement en arrière-plan.
En plus de vos tâches de synchronisation, essayez de combiner vos tâches habituelles
des tâches liées au réseau et les ajouter
onPerformSync()
En concentrant toutes vos tâches réseau avec cette méthode, vous préservez l'autonomie de la batterie
nécessaires pour démarrer et arrêter
les interfaces réseau. Pour en savoir plus sur la façon
de rendre l'accès au réseau plus
consultez la formation Transférer des données sans vider la batterie, qui décrit plusieurs méthodes d'accès réseau
que vous pouvez inclure
dans votre code de transfert de données.
Lier l'adaptateur de synchronisation au framework
Votre code de transfert de données est à présent encapsulé dans un composant d'adaptateur de synchronisation.
pour permettre au framework d'accéder à votre code. Pour ce faire, vous devez créer une limite
Service
qui transmet un objet de liaison Android spécial à partir de l'adaptateur de synchronisation
dans le framework. Avec cet objet de liaison, le framework peut appeler
la méthode onPerformSync()
et
de lui transmettre des données.
Instanciez votre composant d'adaptateur de synchronisation en tant que singleton dans le
Méthode onCreate()
du service. En instanciant
composant dans onCreate()
, vous différez
jusqu'au démarrage du service, ce qui se produit lorsque le framework tente d'exécuter pour la première fois votre
transfert de données. Vous devez instancier le composant de façon thread-safe, au cas où la synchronisation
le framework d'adaptateur place en file d'attente plusieurs exécutions de votre adaptateur de synchronisation en réponse à des déclencheurs ou
la planification.
Par exemple, l'extrait de code suivant vous montre comment créer une classe qui implémente la classe
lié Service
, instancie le composant de l'adaptateur de synchronisation et récupère
Objet de liaison 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(); } }
Remarque:Pour voir un exemple plus détaillé d'un service lié à un adaptateur de synchronisation, consultez l'application exemple.
Ajouter le compte requis par le framework
Le framework d'adaptateurs de synchronisation nécessite que chaque adaptateur de synchronisation soit associé à un type de compte. Vous avez déclaré
la valeur du type de compte dans la section
Ajoutez le fichier de métadonnées Authenticator. Vous devez maintenant configurer ce type de compte
Système Android. Pour configurer le type de compte, ajoutez un compte réservé qui utilise le type de compte
en appelant addAccountExplicitly()
.
Le meilleur endroit pour appeler la méthode est dans la
onCreate()
de la méthode
l'activité d'ouverture. L'extrait de code suivant vous montre comment procéder:
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. */ } } ... }
Ajouter le fichier de métadonnées de l'adaptateur de synchronisation
Pour connecter votre composant d'adaptateur de synchronisation au framework, vous devez fournir le framework
avec des métadonnées qui décrivent le composant et fournissent des options supplémentaires. Les métadonnées spécifient
le type de compte que vous avez créé pour votre adaptateur de synchronisation, déclare une autorité de fournisseur de contenu
associé à votre application, contrôle une partie de l'interface utilisateur du système liée aux adaptateurs de synchronisation,
et déclare d'autres options liées à la synchronisation. Déclarez ces métadonnées dans un fichier XML spécial stocké dans
le répertoire /res/xml/
dans votre projet d'application. Vous pouvez donner n’importe
quel nom au fichier,
bien qu'elle porte généralement le nom syncadapter.xml
.
Ce fichier XML contient un seul élément XML <sync-adapter>
dont le
les attributs suivants:
android:contentAuthority
-
Autorité d'URI de votre fournisseur de contenu. Si vous avez créé un fournisseur
de contenu bouchon pour
votre application lors de la leçon précédente Créer un fournisseur de contenu stub, utilisez la valeur spécifiée pour le paramètre
attribut
android:authorities
dans l'élément<provider>
que vous avez ajouté au fichier manifeste de votre application. Cet attribut est décrits plus en détail dans la section Déclarez le fournisseur dans le fichier manifeste.
Si vous transférez des données d'un fournisseur de contenu vers un serveur à l'aide de votre adaptateur de synchronisation, doit être identique à l'autorité d'URI de contenu que vous utilisez pour ces données. Cette valeur est également l'une des autorités que vous spécifiez dans leandroid:authorities
de l'élément<provider>
qui déclare votre fournisseur dans le fichier manifeste de votre application. android:accountType
-
Type de compte requis par le framework d'adaptateur de synchronisation. La valeur doit être identique
comme valeur de type de compte que vous avez fournie lors de la création du fichier de métadonnées de l'authentificateur,
décrit dans la section Ajouter le fichier de métadonnées Authenticator. Il s'agit également de la valeur que vous avez spécifiée pour le paramètre
constante
ACCOUNT_TYPE
dans l'extrait de code de la section Ajoutez le compte requis par le cadre. - Attributs des paramètres
-
-
android:userVisible
- Définit la visibilité du type de compte de l'adaptateur de synchronisation. Par défaut, l'icône de compte et le libellé associés au type de compte sont visibles dans Dans la section Comptes de l'application Paramètres du système, effectuez la synchronisation l'adaptateur invisible, sauf si vous avez un type de compte ou un domaine facilement associé avec votre application. Si vous rendez votre type de compte invisible, vous pouvez toujours autoriser les utilisateurs à contrôler votre adaptateur de synchronisation avec une interface utilisateur dans l'une des activités de votre application.
-
android:supportsUploading
-
Vous permet d'importer des données dans le cloud. Définissez cette valeur sur
false
si votre application uniquement télécharge des données. -
android:allowParallelSyncs
- Permet à plusieurs instances du composant d'adaptateur de synchronisation de s'exécuter simultanément. Utilisez cette option si votre application prend en charge plusieurs comptes utilisateur et que vous souhaitez autoriser plusieurs de transférer des données en parallèle. Cet indicateur n'a aucun effet si vous n'exécutez jamais plusieurs transferts de données.
-
android:isAlwaysSyncable
-
Indique au framework d'adaptateur de synchronisation qu'il peut exécuter votre adaptateur de synchronisation à tout moment
que vous avez spécifiée. Si vous souhaitez programmer le moment où votre synchronisation
l'adaptateur peut s'exécuter, définissez cet indicateur sur
false
, puis appelezrequestSync()
pour exécuter adaptateur de synchronisation. Pour en savoir plus sur l'exécution d'un adaptateur de synchronisation, consultez la leçon Exécuter un adaptateur de synchronisation
-
L'exemple suivant présente le code XML d'un adaptateur de synchronisation qui utilise un seul compte à espace réservé et ne fait que les téléchargements.
<?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"/>
Déclarer l'adaptateur de synchronisation dans le fichier manifeste
Une fois que vous avez ajouté le composant d'adaptateur de synchronisation à votre application, vous devez demander des autorisations
lié à l'utilisation du composant, et vous devez déclarer le Service
lié
que vous avez ajoutés.
Comme le composant d'adaptateur de synchronisation exécute du code qui transfère les données entre le réseau et le appareil, vous devez demander l'autorisation d'accéder à Internet. De plus, votre application doit pour demander l'autorisation de lire et d'écrire les paramètres de l'adaptateur de synchronisation afin que vous puissiez contrôler la synchronisation l'adaptateur de manière programmatique à partir d'autres composants de votre application. Vous devez également demander un autorisation spéciale permettant à votre appli d'utiliser le composant Authenticator que vous avez créé reportez-vous à la leçon Créer un authentificateur stub.
Pour demander ces autorisations, ajoutez les éléments suivants au fichier manifeste de votre application en tant qu'éléments enfants de
<manifest>
:
-
android.permission.INTERNET
- Autorise le code de l'adaptateur de synchronisation à accéder à Internet pour télécharger ou importer des données de l'appareil à un serveur. Vous n'avez pas besoin de l'ajouter à nouveau l'ayant déjà demandé.
-
android.permission.READ_SYNC_SETTINGS
-
Permet à votre application de lire les paramètres actuels de l'adaptateur de synchronisation. Par exemple, vous avez besoin que
l'autorisation pour appeler
getIsSyncable()
. -
android.permission.WRITE_SYNC_SETTINGS
-
Permet à votre application de contrôler les paramètres de l'adaptateur de synchronisation. Vous avez besoin de cette autorisation pour :
définir des exécutions de l'adaptateur de synchronisation périodique à l'aide de
addPeriodicSync()
. Cette autorisation n'est pas requise pour appelerrequestSync()
Pour en savoir plus sur exécutant l'adaptateur de synchronisation, consultez la section Exécuter un adaptateur de synchronisation.
L'extrait de code suivant montre comment ajouter ces autorisations:
<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>
Enfin, pour déclarer la Service
liée que le framework utilise pour
interagissent avec votre adaptateur de synchronisation, ajoutez le code XML suivant au fichier manifeste de votre application en tant qu'élément enfant.
sur <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>
configure un filtre déclenché par l'action d'intent.
android.content.SyncAdapter
, envoyé par le système pour exécuter l'adaptateur de synchronisation. Lorsque le filtre
est déclenché, le système démarre le service lié que vous avez créé, qui, dans cet exemple,
SyncService
L'attribut
android:exported="false"
n'autorise que votre application et le système à accéder
Service
L'attribut
android:process=":sync"
indique au système d'exécuter Service
dans un processus partagé global nommé
sync
Si vous avez plusieurs adaptateurs de synchronisation
dans votre application, ils peuvent partager ce processus,
ce qui réduit les frais généraux.
La
<meta-data>
fournit le nom du fichier XML de métadonnées de l'adaptateur de synchronisation que vous avez créé précédemment.
La
android:name
indique que ces métadonnées sont destinées au framework d'adaptateur de synchronisation. La
android:resource
spécifie le nom du fichier de métadonnées.
Tous les composants de votre adaptateur de synchronisation sont à présent installés. La leçon suivante vous explique comment au framework d'adaptateur de synchronisation d'exécuter l'adaptateur, soit en réponse à un événement, soit lors un calendrier régulier.