Synchronisierungsadapter ausführen

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);
    }