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.
Dans les leçons précédentes de ce cours, vous avez appris à créer un composant d'adaptateur de synchronisation encapsule le code de transfert de données, et explique comment ajouter d'autres composants qui vous permettent de Branchez l'adaptateur de synchronisation au système. Vous avez maintenant tout ce dont vous avez besoin pour installer une application qui inclut un adaptateur de synchronisation, mais aucun des codes que vous avez vus n'exécute réellement cet adaptateur.
Essayez d'exécuter votre adaptateur de synchronisation selon une programmation ou comme résultat indirect d'une . Par exemple, vous souhaitez peut-être que votre adaptateur de synchronisation s'exécute de façon régulière, soit après une pour une certaine période ou une heure précise de la journée. Vous pouvez également exécuter votre synchronisation adaptateur en cas de modification des données stockées sur l'appareil. Évitez d'exécuter votre l'adaptateur de synchronisation à la suite d'une action de l'utilisateur, car vous n'obtiendrez pas de la capacité de planification du framework d'adaptateur de synchronisation. Par exemple, vous devez éviter fournir un bouton d'actualisation dans votre interface utilisateur.
Vous disposez des options suivantes pour exécuter votre adaptateur de synchronisation:
- Lorsque les données du serveur changent
- Exécutez l'adaptateur de synchronisation en réponse à un message provenant d'un serveur, indiquant que l'état du serveur les données ont changé. Cette option vous permet d'actualiser les données du serveur vers l'appareil sans dégrader les performances ni de gaspiller l'autonomie de la batterie en interrogeant le serveur.
- Lorsque les données de l'appareil changent
- Exécutez un adaptateur de synchronisation lorsque les données changent sur l'appareil. Cette option vous permet d'envoyer des données modifiées entre l'appareil et un serveur, ce qui est particulièrement utile si vous devez vous assurer que le serveur dispose toujours des données les plus récentes de l'appareil. Cette option est simple à utiliser si vous stockez des données chez votre fournisseur de contenu. Si vous utilisez un bouchon fournisseur de contenu, détecter les modifications apportées aux données peut être plus difficile.
- À intervalles réguliers
- Exécutez un adaptateur de synchronisation à l'expiration de l'intervalle de votre choix ou à une certaine fréquence chaque jour.
- À la demande
- Exécutez l'adaptateur de synchronisation en réponse à une action de l'utilisateur. Toutefois, pour offrir aux utilisateurs vous devez privilégier l'une des options les plus automatisées. En utilisant les options d'automatisation, vous préservez la batterie et les ressources réseau.
Le reste de cette leçon décrit chacune de ces options plus en détail.
Exécuter l'adaptateur de synchronisation lorsque les données du serveur changent
Si votre application transfère des données à partir d'un serveur et que les données du serveur changent fréquemment, vous pouvez utiliser
un adaptateur de synchronisation pour effectuer
des téléchargements en réponse aux modifications de données. Pour exécuter l'adaptateur de synchronisation,
le serveur envoie un message spécial à un BroadcastReceiver
dans votre application.
En réponse à ce message, appelez ContentResolver.requestSync()
pour signaler au framework de l'adaptateur de synchronisation qu'il doit exécuter votre
adaptateur de synchronisation.
Google Cloud Messaging (GCM) fournit à la fois
le serveur et les composants d'appareil dont vous avez
besoin pour faire fonctionner ce système de messagerie. Utilisation de GCM pour déclencher
les transferts est plus fiable et plus efficace
que la scrutation de l'état des serveurs. Pendant le sondage
nécessite un élément Service
toujours actif, GCM utilise un élément
BroadcastReceiver
, qui est activé lorsqu'un message arrive. Pendant le sondage
à intervalles réguliers utilise la batterie, même si aucune mise à jour n'est disponible, GCM n'envoie
messages en cas de besoin.
Remarque:Si vous utilisez GCM pour déclencher votre adaptateur de synchronisation via une diffusion à tous appareils sur lesquels votre application est installée, n'oubliez pas qu'ils reçoivent votre message sur à peu près en même temps. Dans ce cas, plusieurs instances de votre adaptateur de synchronisation peuvent s'exécuter en même temps, entraînant une surcharge du serveur et du réseau. Pour éviter cette situation lors d'une diffusion, sur tous les appareils, nous vous recommandons de reporter le démarrage de l'adaptateur de synchronisation. propre à chaque appareil.
L'extrait de code suivant vous montre comment exécuter
requestSync()
en réponse à une
message GCM entrant:
Kotlin
... // Constants // Content provider authority const val AUTHORITY = "com.example.android.datasync.provider" // Account type const val ACCOUNT_TYPE = "com.example.android.datasync" // Account const val ACCOUNT = "default_account" // Incoming Intent key for extended data const val KEY_SYNC_REQUEST = "com.example.android.datasync.KEY_SYNC_REQUEST" ... class GcmBroadcastReceiver : BroadcastReceiver() { ... override fun onReceive(context: Context, intent: Intent) { // Get a GCM object instance val gcm: GoogleCloudMessaging = GoogleCloudMessaging.getInstance(context) // Get the type of GCM message val messageType: String? = gcm.getMessageType(intent) /* * Test the message type and examine the message contents. * Since GCM is a general-purpose messaging system, you * may receive normal messages that don't require a sync * adapter run. * The following code tests for a a boolean flag indicating * that the message is requesting a transfer from the device. */ if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE == messageType && intent.getBooleanExtra(KEY_SYNC_REQUEST, false)) { /* * Signal the framework to run your sync adapter. Assume that * app initialization has already created the account. */ ContentResolver.requestSync(mAccount, AUTHORITY, null) ... } ... } ... }
Java
public class GcmBroadcastReceiver extends BroadcastReceiver { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Account type public static final String ACCOUNT_TYPE = "com.example.android.datasync"; // Account public static final String ACCOUNT = "default_account"; // Incoming Intent key for extended data public static final String KEY_SYNC_REQUEST = "com.example.android.datasync.KEY_SYNC_REQUEST"; ... @Override public void onReceive(Context context, Intent intent) { // Get a GCM object instance GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); // Get the type of GCM message String messageType = gcm.getMessageType(intent); /* * Test the message type and examine the message contents. * Since GCM is a general-purpose messaging system, you * may receive normal messages that don't require a sync * adapter run. * The following code tests for a a boolean flag indicating * that the message is requesting a transfer from the device. */ if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType) && intent.getBooleanExtra(KEY_SYNC_REQUEST)) { /* * Signal the framework to run your sync adapter. Assume that * app initialization has already created the account. */ ContentResolver.requestSync(mAccount, AUTHORITY, null); ... } ... } ... }
Exécuter l'adaptateur de synchronisation lorsque les données du fournisseur de contenu sont modifiées
Si votre application collecte des données auprès d'un fournisseur de contenu et que vous souhaitez mettre à jour le serveur
vous mettez à jour le fournisseur, vous pouvez configurer votre application pour qu'elle exécute votre adaptateur de synchronisation automatiquement. À faire
vous enregistrez un observateur pour le fournisseur de contenu. Lorsque des données de votre fournisseur de contenu
le framework du fournisseur de contenu appelle l'observateur. Dans l'observateur, appelez
requestSync()
pour indiquer au framework de s'exécuter
votre adaptateur de synchronisation.
Remarque:Si vous utilisez un fournisseur de contenu bouchon, vous n'avez aucune donnée dans
le fournisseur de contenu, et onChange()
jamais appelé. Dans ce cas, vous devez fournir votre propre mécanisme
pour détecter les modifications de
les données de l'appareil. Ce mécanisme permet également d'appeler
requestSync()
lorsque les données changent.
Pour créer un observateur pour votre fournisseur de contenu, étendez la classe
ContentObserver
et implémenter les deux formes de son
onChange()
. Dans
onChange()
, appeler
requestSync()
pour démarrer l'adaptateur de synchronisation.
Pour enregistrer l'observateur, transmettez-le en tant qu'argument dans un appel à
registerContentObserver()
Dans
cet appel, vous devez également transmettre un URI de contenu pour les données que vous souhaitez surveiller. Le contenu
Provider Framework compare cet URI de montre aux URI de contenu transmis en tant qu'arguments à
ContentResolver
qui modifient votre fournisseur, telles que
ContentResolver.insert()
Si une correspondance est trouvée, votre
implémentation de ContentObserver.onChange()
est appelé.
L'extrait de code suivant vous montre comment définir un ContentObserver
qui appelle requestSync()
lorsqu'une table
modifications:
Kotlin
// Constants // Content provider scheme const val SCHEME = "content://" // Content provider authority const val AUTHORITY = "com.example.android.datasync.provider" // Path for the content provider table const val TABLE_PATH = "data_table" ... class MainActivity : FragmentActivity() { ... // A content URI for the content provider's data table private lateinit var uri: Uri // A content resolver for accessing the provider private lateinit var mResolver: ContentResolver ... inner class TableObserver(...) : ContentObserver(...) { /* * Define a method that's called when data in the * observed content provider changes. * This method signature is provided for compatibility with * older platforms. */ override fun onChange(selfChange: Boolean) { /* * Invoke the method signature available as of * Android platform version 4.1, with a null URI. */ onChange(selfChange, null) } /* * Define a method that's called when data in the * observed content provider changes. */ override fun onChange(selfChange: Boolean, changeUri: Uri?) { /* * Ask the framework to run your sync adapter. * To maintain backward compatibility, assume that * changeUri is null. */ ContentResolver.requestSync(account, AUTHORITY, null) } ... } ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... // Get the content resolver object for your app mResolver = contentResolver // Construct a URI that points to the content provider data table uri = Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .path(TABLE_PATH) .build() /* * Create a content observer object. * Its code does not mutate the provider, so set * selfChange to "false" */ val observer = TableObserver(false) /* * Register the observer for the data table. The table's path * and any of its subpaths trigger the observer. */ mResolver.registerContentObserver(uri, true, observer) ... } ... }
Java
public class MainActivity extends FragmentActivity { ... // Constants // Content provider scheme public static final String SCHEME = "content://"; // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Path for the content provider table public static final String TABLE_PATH = "data_table"; // Account public static final String ACCOUNT = "default_account"; // Global variables // A content URI for the content provider's data table Uri uri; // A content resolver for accessing the provider ContentResolver mResolver; ... public class TableObserver extends ContentObserver { /* * Define a method that's called when data in the * observed content provider changes. * This method signature is provided for compatibility with * older platforms. */ @Override public void onChange(boolean selfChange) { /* * Invoke the method signature available as of * Android platform version 4.1, with a null URI. */ onChange(selfChange, null); } /* * Define a method that's called when data in the * observed content provider changes. */ @Override public void onChange(boolean selfChange, Uri changeUri) { /* * Ask the framework to run your sync adapter. * To maintain backward compatibility, assume that * changeUri is null. */ ContentResolver.requestSync(mAccount, AUTHORITY, null); } ... } ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Get the content resolver object for your app mResolver = getContentResolver(); // Construct a URI that points to the content provider data table uri = new Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .path(TABLE_PATH) .build(); /* * Create a content observer object. * Its code does not mutate the provider, so set * selfChange to "false" */ TableObserver observer = new TableObserver(false); /* * Register the observer for the data table. The table's path * and any of its subpaths trigger the observer. */ mResolver.registerContentObserver(uri, true, observer); ... } ... }
Exécuter régulièrement l'adaptateur de synchronisation
Vous pouvez exécuter régulièrement votre adaptateur de synchronisation en définissant un délai d'attente entre les exécutions. ou en l'exécutant à certains moments de la journée, ou les deux. Exécuter l'adaptateur de synchronisation permet régulièrement de correspondre à peu près à l'intervalle de mise à jour de votre serveur.
De même, vous pouvez importer des données depuis l'appareil lorsque votre serveur est relativement inactif : planifier l'exécution de votre adaptateur de synchronisation la nuit. La plupart des utilisateurs laissent leur appareil allumé et branché la nuit. C'est donc généralement disponible à cette heure. De plus, l'appareil n'exécute aucune autre tâche dans en même temps que votre adaptateur de synchronisation. Toutefois, si vous adoptez cette approche, chaque appareil déclenche un transfert de données à un moment légèrement différent. Si tous les appareils exécutent votre l'adaptateur secteur en parallèle, vous risquez de surcharger les données de votre serveur et de votre opérateur mobile. réseaux sociaux.
En général, les exécutions périodiques sont utiles si vos utilisateurs n'ont pas besoin de mises à jour instantanées, mais qu'ils s'attendent à des mises à jour régulières. Les exécutions périodiques sont également utiles si vous voulez équilibrer la disponibilité des données actualisées grâce à l'efficacité d'un adaptateur de synchronisation plus petit qui n'utilise pas trop l'appareil. ressources.
Pour faire fonctionner l'adaptateur de synchronisation à intervalles réguliers, appelez
addPeriodicSync()
Cela planifie votre
l'adaptateur de synchronisation doit s'exécuter après un certain temps. Étant donné que le framework d'adaptateur de synchronisation
prend en compte d'autres exécutions de l'adaptateur de synchronisation
et tente d'optimiser l'efficacité de la batterie,
le temps écoulé peut varier de quelques secondes. En outre, le framework n'exécutera pas votre adaptateur de synchronisation si le
réseau non disponible.
Notez que addPeriodicSync()
n'a pas
exécuter l'adaptateur de synchronisation
à un moment précis de la journée. Pour que l'adaptateur de synchronisation fonctionne à environ
chaque jour à la même heure, utilisez une alarme récurrente comme déclencheur. Les alarmes répétées sont décrites plus en détail
consultez la documentation de référence sur AlarmManager
. Si vous utilisez les
la méthode setInexactRepeating()
pour définir
de l'heure de début avec des variations, vous devez toujours randomiser l'heure de
assurez-vous que l'adaptateur de synchronisation fonctionne sur différents appareils.
La méthode addPeriodicSync()
ne permet pas
désactiver setSyncAutomatically()
,
Vous pouvez donc exécuter plusieurs synchronisations
dans un laps de temps relativement court. Par ailleurs, seuls quelques
les indicateurs de contrôle de l'adaptateur de synchronisation sont autorisés dans un appel
addPeriodicSync()
; les indicateurs
ne sont pas autorisés sont décrits dans la documentation de référence
addPeriodicSync()
L'extrait de code suivant montre comment planifier des exécutions périodiques de l'adaptateur de synchronisation:
Kotlin
// Content provider authority const val AUTHORITY = "com.example.android.datasync.provider" // Account const val ACCOUNT = "default_account" // Sync interval constants const val SECONDS_PER_MINUTE = 60L const val SYNC_INTERVAL_IN_MINUTES = 60L const val SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * SECONDS_PER_MINUTE ... class MainActivity : FragmentActivity() { ... // A content resolver for accessing the provider private lateinit var mResolver: ContentResolver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... // Get the content resolver for your app mResolver = contentResolver /* * Turn on periodic syncing */ ContentResolver.addPeriodicSync( mAccount, AUTHORITY, Bundle.EMPTY, SYNC_INTERVAL) ... } ... }
Java
public class MainActivity extends FragmentActivity { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Account public static final String ACCOUNT = "default_account"; // Sync interval constants public static final long SECONDS_PER_MINUTE = 60L; public static final long SYNC_INTERVAL_IN_MINUTES = 60L; public static final long SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * SECONDS_PER_MINUTE; // Global variables // A content resolver for accessing the provider ContentResolver mResolver; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // Get the content resolver for your app mResolver = getContentResolver(); /* * Turn on periodic syncing */ ContentResolver.addPeriodicSync( mAccount, AUTHORITY, Bundle.EMPTY, SYNC_INTERVAL); ... } ... }
Exécuter l'adaptateur de synchronisation à la demande
La stratégie la moins conseillée est d'exécuter votre adaptateur de synchronisation en réponse à la demande d'un utilisateur. pour exécuter un adaptateur de synchronisation. Le framework est spécialement conçu pour préserver l'autonomie de la batterie. lorsqu'il exécute des adaptateurs de synchronisation selon un calendrier. Options qui exécutent une synchronisation en réponse aux données utilisent efficacement la batterie, car celle-ci sert à fournir de nouvelles données.
En revanche, si vous permettez aux utilisateurs d'exécuter une synchronisation à la demande, la synchronisation s'exécute seule, ce qui est une utilisation inefficace des ressources réseau et énergétiques. De plus, la synchronisation à la demande conduit les utilisateurs demander une synchronisation même si rien n'indique que les données ont changé et exécuter une synchronisation qui n'actualise pas les données est une utilisation inefficace de la batterie. En général, votre application doit : utiliser d'autres signaux pour déclencher une synchronisation ou les planifier à intervalles réguliers, sans intervention de l'utilisateur.
Toutefois, si vous souhaitez toujours exécuter l'adaptateur de synchronisation à la demande, définissez les indicateurs correspondants pour une
manuellement l'adaptateur de synchronisation, puis appelez
ContentResolver.requestSync()
Exécuter des transferts à la demande avec les options suivantes:
-
SYNC_EXTRAS_MANUAL
-
Force une synchronisation manuelle. Le framework d'adaptateur de synchronisation
ignore les paramètres existants,
comme l'option définie par
setSyncAutomatically()
. -
SYNC_EXTRAS_EXPEDITED
- Force le démarrage immédiat de la synchronisation. Si vous ne définissez pas cette valeur, le système peut attendre plusieurs secondes avant d'exécuter la demande de synchronisation, car elle essaie d'optimiser l'utilisation de la batterie en planifier de nombreuses requêtes en peu de temps.
L'extrait de code suivant vous montre comment appeler
requestSync()
en réponse à un bouton
cliquez sur:
Kotlin
// Constants // Content provider authority val AUTHORITY = "com.example.android.datasync.provider" // Account type val ACCOUNT_TYPE = "com.example.android.datasync" // Account val ACCOUNT = "default_account" ... class MainActivity : FragmentActivity() { ... // Instance fields private lateinit var mAccount: Account ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... /* * Create the placeholder account. The code for CreateSyncAccount * is listed in the lesson Creating a Sync Adapter */ mAccount = createSyncAccount() ... } /** * Respond to a button click by calling requestSync(). This is an * asynchronous operation. * * This method is attached to the refresh button in the layout * XML file * * @param v The View associated with the method call, * in this case a Button */ fun onRefreshButtonClick(v: View) { // Pass the settings flags by inserting them in a bundle val settingsBundle = Bundle().apply { putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true) putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true) } /* * Request the sync for the default account, authority, and * manual sync settings */ ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle) }
Java
public class MainActivity extends FragmentActivity { ... // Constants // Content provider authority public static final String AUTHORITY = "com.example.android.datasync.provider"; // Account type public static final String ACCOUNT_TYPE = "com.example.android.datasync"; // Account public static final String ACCOUNT = "default_account"; // Instance fields Account mAccount; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... /* * Create the placeholder account. The code for CreateSyncAccount * is listed in the lesson Creating a Sync Adapter */ mAccount = CreateSyncAccount(this); ... } /** * Respond to a button click by calling requestSync(). This is an * asynchronous operation. * * This method is attached to the refresh button in the layout * XML file * * @param v The View associated with the method call, * in this case a Button */ public void onRefreshButtonClick(View v) { // Pass the settings flags by inserting them in a bundle Bundle settingsBundle = new Bundle(); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_MANUAL, true); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_EXPEDITED, true); /* * Request the sync for the default account, authority, and * manual sync settings */ ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle); }