Hinweis:Wir empfehlen WorkManager. ist die empfohlene Lösung für die meisten Anwendungsfälle der Hintergrundverarbeitung. Bitte beachten Sie die Leitfaden zur Hintergrundverarbeitung, um zu erfahren, welche Lösung für Sie am besten geeignet ist.
In den vorherigen Lektionen dieses Kurses haben Sie gelernt, wie Sie eine Komponente für den Synchronisierungsadapter erstellen, die Datenübertragungscode verkapselt und wie Sie die zusätzlichen Komponenten hinzufügen, mit denen Sie schließen Sie den Synchronisierungsadapter an das System an. Jetzt haben Sie alles, was Sie brauchen, um eine App zu installieren, enthält einen Synchronisierungsadapter, aber bei keinem der Codes wird der Synchronisierungsadapter ausgeführt.
Sie sollten versuchen, den Synchronisierungsadapter nach einem Zeitplan oder als indirektes Ergebnis einer . Sie möchten den Synchronisierungsadapter beispielsweise regelmäßig ausführen, entweder nach einem für einen bestimmten Zeitraum oder zu einer bestimmten Tageszeit. Sie können auch Ihre Synchronisierung durchführen. wenn es Änderungen an den auf dem Gerät gespeicherten Daten gibt. Vermeiden Sie es, als direkte Folge einer Nutzeraktion, da Sie so nicht den vollen Vorteil der Planungsfunktion des Frameworks für den Synchronisierungsadapter. Vermeiden Sie beispielsweise über eine Schaltfläche zum Aktualisieren in der Benutzeroberfläche.
Sie haben folgende Möglichkeiten, den Synchronisierungsadapter auszuführen:
- Wenn sich Serverdaten ändern
- Führen Sie den Sync-Adapter als Antwort auf eine Nachricht von einem Server aus, die angibt, dass ein serverbasierter Daten geändert. Mit dieser Option können Sie Daten vom Server auf dem Gerät aktualisieren ohne die Leistung zu beeinträchtigen oder Akkulaufzeit zu vergeuden, indem sie den Server abfragen.
- Wenn sich Gerätedaten ändern
- Führen Sie einen Synchronisierungsadapter aus, wenn sich Daten auf dem Gerät ändern. Mit dieser Option können Sie modifizierte Daten vom Gerät zu einem Server. Dies ist besonders nützlich, wenn Sie sicherstellen müssen, dass der Server immer die neuesten Gerätedaten hat. Diese Option lässt sich leicht implementieren, wenn Sie Daten bei Ihrem Contentanbieter speichern. Wenn Sie einen -Stub verwenden, Content-Providers handelt, ist das Erkennen von Datenänderungen möglicherweise schwieriger.
- In regelmäßigen Abständen
- Führen Sie einen Synchronisierungsadapter nach Ablauf eines ausgewählten Intervalls aus oder führen Sie ihn zu einem bestimmten -mal pro Tag.
- On demand
- Führen Sie den Synchronisierungsadapter als Reaktion auf eine Nutzeraktion aus. Um jedoch den bestmöglichen sollten Sie sich hauptsächlich auf eine der automatisierten Optionen verlassen. Durch die Verwendung von Automatisierte Optionen schonen den Akku und die Netzwerkressourcen.
Im weiteren Verlauf dieser Lektion werden die einzelnen Optionen ausführlicher beschrieben.
Synchronisierungsadapter ausführen, wenn sich Serverdaten ändern
Wenn Ihre App Daten von einem Server überträgt und sich die Serverdaten häufig ändern, können Sie
einen Synchronisierungsadapter, um Downloads als Reaktion auf Datenänderungen durchzuführen. Um den Synchronisierungsadapter auszuführen, müssen Sie
sendet der Server eine spezielle Nachricht an BroadcastReceiver
in Ihrer App.
Rufen Sie als Antwort auf diese Nachricht ContentResolver.requestSync()
auf, um dem Framework des Synchronisierungsadapters zu signalisieren, dass Ihr
Sync Adapter.
Google Cloud Messaging (GCM) bietet sowohl die
Server- und Gerätekomponenten, die Sie benötigen,
damit dieses Nachrichtensystem funktioniert. GCM zum Auslösen verwenden
sind zuverlässiger und effizienter als das Abfragen des Status von Servern. Beim Abfragen
ein Service
, das immer aktiv ist, verwendet GCM einen
BroadcastReceiver
, die beim Eingang einer Nachricht aktiviert wird. Beim Abfragen
verbraucht in regelmäßigen Abständen Akkuleistung, auch wenn keine Updates verfügbar sind, sendet GCM
Nachrichten senden.
Hinweis: Wenn Sie GCM verwenden, um Ihren Synchronisierungsadapter über eine Übertragung an alle Geräte, auf denen Ihre App installiert ist, erhalten Sie Ihre Nachricht unter ungefähr zur gleichen Zeit. Diese Situation kann dazu führen, dass mehrere Instanzen des Synchronisierungsadapters ausgeführt werden Server- und Netzwerküberlastung verursachen. Um das bei einer Übertragung zu vermeiden für alle Geräte aktiviert haben, sollten Sie den Start des Synchronisierungsadapters auf einen bestimmten die für jedes Gerät eindeutig ist.
Das folgende Code-Snippet zeigt, wie Sie
requestSync()
als Antwort auf einen
eingehende GCM-Nachricht:
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); ... } ... } ... }
Synchronisierungsadapter ausführen, wenn Daten des Contentanbieters geändert werden
Wenn Ihre App Daten bei einem Contentanbieter erhebt und Sie den Server jedes Mal aktualisieren möchten,
Sie den Anbieter aktualisieren, können Sie Ihre App so einrichten, dass Ihr Synchronisierungsadapter automatisch ausgeführt wird. Aufgabe
registrieren Sie einen Beobachter für den Contentanbieter. Wenn Daten bei Ihrem Contentanbieter
bezeichnet das Contentanbieter-Framework den Beobachter. Rufen Sie im Beobachter
requestSync()
, um das Framework anzuweisen, die Ausführung
den Synchronisierungsadapter verwenden.
Hinweis:Wenn Sie einen Stub-Contentanbieter verwenden,
der Contentanbieter und onChange()
nie angerufen. In diesem Fall müssen Sie einen eigenen Mechanismus
zur Erkennung von Änderungen
Gerätedaten. Dieser Mechanismus ist auch für den Aufruf von
requestSync()
, wenn sich die Daten ändern.
Erweitern Sie die Klasse, um einen Beobachter für Ihren Contentanbieter zu erstellen.
ContentObserver
und beide Formen der zugehörigen
onChange()
-Methode. In
onChange()
, Anruf
requestSync()
, um den Synchronisierungsadapter zu starten.
Um den Beobachter zu registrieren, übergeben Sie ihn als Argument in einem Aufruf an
registerContentObserver()
In
müssen Sie auch einen Inhalts-URI für die Daten übergeben, die Sie sich ansehen möchten. Inhalt
Anbieter-Framework diesen Beobachtungs-URI mit Inhalts-URIs, die als Argumente an
ContentResolver
-Methoden, die Ihren Anbieter ändern, z. B.
ContentResolver.insert()
. Bei einer Übereinstimmung
Implementierung von ContentObserver.onChange()
aufgerufen wird.
Im folgenden Code-Snippet sehen Sie, wie ein ContentObserver
definiert wird
die requestSync()
aufruft, wenn eine Tabelle
Änderungen:
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); ... } ... }
Synchronisierungsadapter regelmäßig ausführen
Sie können den Synchronisierungsadapter regelmäßig ausführen, indem Sie einen Zeitraum festlegen, der zwischen Ausführungen gewartet werden soll. und/oder sie zu bestimmten Tageszeiten ausführen. Synchronisierungsadapter ausführen können Sie das Aktualisierungsintervall Ihres Servers ungefähr an das von Ihnen festgelegte Server halten.
Ebenso können Sie Daten vom Gerät hochladen, wenn Ihr Server relativ inaktiv ist, indem Sie Ihren Synchronisierungsadapter nachts ausführen. Die meisten Nutzer lassen ihr Gerät eingeschaltet und an die Stromversorgung angeschlossen nachts, also ist diese Uhrzeit normalerweise verfügbar. Außerdem führt das Gerät keine anderen Aufgaben und den Synchronisierungsadapter verwenden. Wenn Sie diesen Ansatz wählen, müssen Sie jedoch sicherstellen, löst jedes Gerät eine Datenübertragung zu einer etwas anderen Zeit aus. Wenn auf allen Geräten Synchronisierungsadapter verwenden, werden Ihre Server- und Mobilfunkdaten Netzwerken.
Im Allgemeinen sind regelmäßige Ausführungen sinnvoll, wenn Ihre Nutzer keine sofortigen Updates benötigen, aber davon ausgehen, werden regelmäßig aktualisiert. Regelmäßige Ausführungen sind auch sinnvoll, wenn Sie die Verfügbarkeit Aktuelle Daten mit der Effizienz kleinerer Synchronisierungsadapterausführungen, die das Gerät nicht übermäßig beanspruchen Ressourcen.
Um den Synchronisierungsadapter in regelmäßigen Abständen auszuführen, rufen Sie folgenden Befehl auf:
addPeriodicSync()
Dadurch wird Ihr
um nach einer gewissen Zeit ausgeführt zu werden. Da das Framework des Synchronisierungsadapters
andere Ausführungen des Synchronisierungsadapters berücksichtigen müssen und versuchen, die Akkueffizienz zu maximieren,
kann um einige Sekunden variieren. Außerdem führt das Framework Ihren Synchronisierungsadapter nicht aus, wenn der
Netzwerk ist nicht verfügbar.
Beachten Sie, dass addPeriodicSync()
keine
den Synchronisierungsadapter zu einer bestimmten Tageszeit ausführen. Um den Synchronisierungsadapter mit ungefähr
jeden Tag zur gleichen Zeit einen Wecker auslösen, der sich wiederholen kann. Sich wiederholende Alarme werden im weiteren
in der Referenzdokumentation zu AlarmManager
. Wenn Sie das
setInexactRepeating()
-Methode festlegen
zu bestimmten Tageszeiten ausgelöst werden,
sollten Sie die Startzeit dennoch zufällig festlegen,
stellen Sie sicher, dass der Synchronisierungsadapter auf verschiedenen Geräten ausgeführt wird.
Die Methode addPeriodicSync()
enthält keine
setSyncAutomatically()
deaktivieren,
sodass Sie in relativ kurzer Zeit
mehrere Synchronisierungsläufe erhalten können. Außerdem werden nur einige
Steuerungs-Flags des Synchronisierungsadapters in einem Aufruf von
addPeriodicSync()
; die Flags, die
sind in der Dokumentation zu
addPeriodicSync()
.
Das folgende Code-Snippet zeigt, wie Sie regelmäßige Synchronisierungs-Adapterausführungen planen:
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); ... } ... }
Synchronisierungsadapter bei Bedarf ausführen
Die Ausführung des Synchronisierungsadapters als Reaktion auf eine Nutzeranfrage ist die am wenigsten bevorzugte Strategie. zum Ausführen eines Synchronisierungsadapters. Das Framework ist speziell darauf ausgelegt, den Akku zu schonen. wenn Synchronisierungsadapter nach einem Zeitplan ausgeführt werden. Optionen, die eine Synchronisierung als Reaktion auf Daten ausführen Änderungen verbrauchen effektiv die Batterieleistung, da die Energie verwendet wird, um neue Daten bereitzustellen.
Wenn Nutzer hingegen eine Synchronisierung bei Bedarf durchführen können, bedeutet dies, dass die Synchronisierung für sich selbst ausgeführt wird. ist die ineffiziente Nutzung von Netzwerk- und Energieressourcen. Außerdem führt die On-Demand-Synchronisierung eine Synchronisierung anfordern, auch wenn es keine Anzeichen dafür gibt, dass sich die Daten geändert haben, und eine Synchronisierung durchzuführen, Wenn die Daten nicht aktualisiert werden, stellt dies eine ineffektive Nutzung des Akkus dar. Im Allgemeinen sollte Ihre App entweder andere Signale verwenden, um eine Synchronisierung auszulösen oder sie in regelmäßigen Abständen ohne Nutzereingabe zu planen.
Wenn Sie den Synchronisierungsadapter jedoch weiterhin bei Bedarf ausführen möchten, legen Sie die Flags des Synchronisierungsadapters für ein
Adapter für manuelle Synchronisierung ausführen und dann aufrufen
ContentResolver.requestSync()
Führen Sie On-Demand-Übertragungen mit den folgenden Flags aus:
-
SYNC_EXTRAS_MANUAL
-
Erzwingt eine manuelle Synchronisierung. Das Framework für den Synchronisierungsadapter ignoriert die vorhandenen Einstellungen,
z. B. das von
setSyncAutomatically()
festgelegte Flag. -
SYNC_EXTRAS_EXPEDITED
- Erzwingt einen sofortigen Start der Synchronisierung. Wenn Sie diese nicht festlegen, wartet das System möglicherweise mehrere Sekunden vor der Ausführung der Synchronisierungsanfrage, da sie so versucht, den Akkuverbrauch durch die Planung vieler Anfragen innerhalb kurzer Zeit.
Das folgende Code-Snippet zeigt, wie Sie
requestSync()
als Reaktion auf eine Schaltfläche
Klick:
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); }