Tworzenie adaptera synchronizacji

Uwaga: zalecamy WorkManager jako zalecane rozwiązanie w większości przypadków użycia związanych z przetwarzaniem w tle. Zapoznaj się z przewodnikiem dotyczącym przetwarzania w tle, aby sprawdzić, które rozwiązanie jest dla Ciebie najlepsze.

Komponent adaptera synchronizacji w aplikacji zawiera kod dla zadań przesyłających dane między urządzeniem a serwerem. Na podstawie harmonogramu i aktywatorów podanych w aplikacji platforma adaptera synchronizacji uruchamia kod w komponencie adaptera synchronizacji. Aby dodać do aplikacji komponent adaptera synchronizacji, musisz dodać te elementy:

Zsynchronizuj klasę adaptera.
Klasa, która pakuje kod transferu danych w interfejs zgodny ze platformą adaptera synchronizacji.
Powiązano Service.
Komponent, który umożliwia platformie adaptera synchronizacji uruchamianie kodu w klasie adaptera synchronizacji.
Plik XML metadanych adaptera synchronizacji.
Plik zawierający informacje o adapterze synchronizacji. Platforma odczytuje ten plik, aby dowiedzieć się, jak wczytać i zaplanować transfer danych.
Deklaracje w manifeście aplikacji
Plik XML deklarujący powiązaną usługę i wskazujący synchronizację metadanych konkretnego adaptera.

Z tej lekcji dowiesz się, jak zdefiniować te elementy.

Tworzenie klasy adaptera synchronizacji

W tej części lekcji dowiesz się, jak utworzyć klasę adaptera synchronizacji, która zawiera kod transferu danych. Utworzenie klasy obejmuje rozszerzenie klasy podstawowej adaptera synchronizacji, definiowanie jej konstruktorów i wdrożenie metody, w której definiuje się zadania przenoszenia danych.

Rozszerz klasę podstawowej adaptera synchronizacji

Aby utworzyć komponent adaptera synchronizacji, zacznij od rozszerzenia AbstractThreadedSyncAdapter i napisania jego konstruktorów. Używaj konstruktorów do uruchamiania zadań konfiguracji za każdym razem, gdy komponent adaptera synchronizacji jest tworzony od podstaw – tak samo jak robisz to przy użyciu Activity.onCreate() do konfigurowania działania. Jeśli na przykład Twoja aplikacja korzysta z usług dostawcy treści do przechowywania danych, użyj konstruktorów, aby uzyskać wystąpienie ContentResolver. Na platformie Androida w wersji 3.0 dodano drugą formę konstruktora w celu obsługi argumentu parallelSyncs, więc aby zachować zgodność, musisz utworzyć 2 formy konstruktora.

Uwaga: platforma adaptera synchronizacji została zaprojektowana do współpracy z komponentami adaptera synchronizacji, które są instancjami pojedynczymi. Tworzenie instancji komponentu adaptera synchronizacji zostało szczegółowo omówione w sekcji Przypisywanie adaptera synchronizacji z platformą.

Z przykładu poniżej dowiesz się, jak zaimplementować funkcję AbstractThreadedSyncAdapter i jej konstruktory:

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

Dodawanie kodu przenoszenia danych

Komponent adaptera synchronizacji nie przenosi danych automatycznie. Zamiast tego zawiera on kod transferu danych, dzięki czemu platforma adaptera synchronizacji może uruchamiać przesyłanie danych w tle, bez angażowania Twojej aplikacji. Gdy platforma będzie gotowa do synchronizacji danych aplikacji, wywoła implementację metody onPerformSync().

Aby ułatwić przesyłanie danych z głównego kodu aplikacji do komponentu adaptera synchronizacji, platforma adaptera synchronizacji wywołuje onPerformSync() przy użyciu tych argumentów:

Konto
Obiekt Account powiązany ze zdarzeniem, które uruchomiło adapter synchronizacji. Jeśli serwer nie używa kont, nie musisz używać informacji z tego obiektu.
Dodatkowe treści
Element Bundle zawierający flagi wysłane przez zdarzenie, które uruchomiło adapter synchronizacji.
Urząd
Uprawnienia dostawcy treści w systemie. Twoja aplikacja musi mieć dostęp do tego dostawcy. Zwykle urząd odpowiada dostawcy treści w Twojej aplikacji.
Klient dostawcy treści
Wartość ContentProviderClient dla dostawcy treści, na którą wskazuje argument autoryzacyjny. ContentProviderClient to prosty interfejs publiczny dla dostawcy treści. Ma te same podstawowe funkcje co ContentResolver. Jeśli korzystasz z usług dostawcy treści do przechowywania danych o aplikacji, możesz połączyć się z nim za pomocą tego obiektu. W przeciwnym razie możesz go zignorować.
Wynik synchronizacji
Obiekt SyncResult używany do wysyłania informacji do platformy adaptera synchronizacji.

Ten fragment kodu pokazuje ogólną strukturę strony 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.
     */
}

Rzeczywista implementacja onPerformSync() zależy od wymagań aplikacji w zakresie synchronizacji danych i protokołów połączenia z serwerem, jednak musisz wykonać kilka ogólnych zadań:

Łączenie z serwerem
Możesz założyć, że sieć jest dostępna w momencie rozpoczęcia przenoszenia danych, ale platforma adaptera synchronizacji nie łączy się automatycznie z serwerem.
Pobieranie i przesyłanie danych
Adapter synchronizacji nie automatyzuje żadnych zadań związanych z przesyłaniem danych. Jeśli chcesz pobrać dane z serwera i przechowywać je u dostawcy treści, musisz podać kod, który wysyła żądanie danych, pobiera je i wstawia u dostawcy. Analogicznie, jeśli chcesz wysłać dane na serwer, musisz odczytać je z pliku, bazy danych lub dostawcy i wysłać niezbędne żądanie przesłania. Musisz też obsługiwać błędy sieci, które pojawiają się podczas przenoszenia danych.
radzenie sobie z konfliktami danych i określanie ich aktualności,
Adapter synchronizacji nie obsługuje automatycznie konfliktów między danymi na serwerze a danymi na urządzeniu. Nie wykrywa też automatycznie, czy dane na serwerze są nowsze niż dane na urządzeniu, i odwrotnie. Zamiast tego musisz udostępnić własne algorytmy, które będą postępować w takiej sytuacji.
Wyczyść dane.
Zawsze zamykaj połączenia z serwerem oraz czyść pliki tymczasowe i pamięć podręczną na końcu przesyłania danych.

Uwaga: platforma adaptera synchronizacji uruchamia onPerformSync() w wątku w tle, więc nie musisz konfigurować własnego przetwarzania w tle.

Oprócz zadań związanych z synchronizacją warto też połączyć zwykłe zadania związane z siecią i dodać je do zadania onPerformSync(). Koncentrując wszystkie zadania sieciowe na tej metodzie, oszczędzasz baterię potrzebną do uruchamiania i zatrzymywania interfejsów sieciowych. Więcej informacji o zwiększaniu wydajności dostępu do sieci znajdziesz w klasie szkoleniowej Przenoszenie danych bez wyczerpywania baterii. Opisano w niej kilka zadań związanych z dostępem do sieci, które możesz uwzględnić w kodzie transferu danych.

Powiąż adapter synchronizacji z platformą

Twój kod transferu danych jest teraz zawarty w komponencie adaptera synchronizacji, ale musisz zapewnić platformie dostęp do kodu. Aby to zrobić, musisz utworzyć powiązany obiekt Service, który przekazuje do platformy specjalny obiekt powiązania Androida z komponentu adaptera synchronizacji. Dzięki temu obiektowi powiązania platforma może wywołać metodę onPerformSync() i przekazać do niej dane.

Utwórz wystąpienie komponentu adaptera synchronizacji jako single w metodzie onCreate() usługi. Tworząc instancję komponentu w onCreate(), odkładasz jego utworzenie do momentu uruchomienia usługi, co ma miejsce, gdy platforma po raz pierwszy spróbuje uruchomić przesyłanie danych. Musisz utworzyć instancję komponentu w sposób bezpieczny w wątku, na wypadek gdyby platforma adaptera synchronizacji umieszczała w kolejce wiele uruchomień adaptera synchronizacji w odpowiedzi na aktywatory lub harmonogramy.

Ten fragment kodu pokazuje na przykład, jak utworzyć klasę, która implementuje powiązany Service, tworzy instancję komponentu adaptera synchronizacji i pobiera obiekt powiązania Androida:

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

Uwaga: bardziej szczegółowy przykład usługi powiązanej z adapterem synchronizacji znajdziesz w przykładowej aplikacji.

Dodaj konto wymagane przez zasady.

Platforma adaptera synchronizacji wymaga, aby każdy adapter synchronizacji miał określony typ konta. Wartość rodzaju konta zadeklarowano w sekcji Dodawanie pliku metadanych Authenticator. Teraz musisz skonfigurować ten rodzaj konta w systemie Android. Aby skonfigurować rodzaj konta, dodaj konto zastępcze korzystające z tego typu konta, wywołując addAccountExplicitly().

Najlepszym miejscem do jej wywołania jest metoda onCreate() związana z otwieraniem aplikacji. Poniższy fragment kodu pokazuje, jak to zrobić:

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.
             */
        }
    }
    ...
}

Dodaj plik metadanych adaptera synchronizacji

Aby podłączyć komponent adaptera synchronizacji do platformy, musisz udostępnić platformę z metadanymi opisującymi ten komponent i dodatkowymi flagami. Metadane określają typ konta utworzony dla adaptera synchronizacji, deklarują urząd dostawcy treści powiązany z Twoją aplikacją, kontrolują część interfejsu użytkownika systemu związaną z adapterami synchronizacji oraz deklarują inne flagi związane z synchronizacją. Zadeklaruj te metadane w specjalnym pliku XML przechowywanym w katalogu /res/xml/ w projekcie aplikacji. Plikowi możesz nadać dowolną nazwę. Zazwyczaj ma on nazwę syncadapter.xml.

Ten plik XML zawiera pojedynczy element XML <sync-adapter> o następujących atrybutach:

android:contentAuthority
Urządzenie URI dla dostawcy treści. Jeśli w poprzedniej lekcji Tworzenie dostawcy treści Stub został przez Ciebie utworzony dostawcę treści jego aplikacji, użyj wartości określonej dla atrybutu android:authorities w elemencie <provider> dodanym do pliku manifestu aplikacji. Ten atrybut został szczegółowo opisany w sekcji Deklarowanie dostawcy w pliku manifestu.
Jeśli przenosisz dane od dostawcy treści na serwer za pomocą adaptera synchronizacji, ta wartość powinna być taka sama jak wartość identyfikatora URI treści używanego w przypadku tych danych. Ta wartość jest również jednym z organów urzędowych podanych w atrybucie android:authorities elementu <provider>, który deklaruje dostawcę w manifeście aplikacji.
android:accountType
Rodzaj konta wymagany przez platformę adaptera synchronizacji. Wartość musi być taka sama jak wartość rodzaju konta podana podczas tworzenia pliku metadanych uwierzytelniania zgodnie z opisem w sekcji Dodawanie pliku metadanych Authenticator. Jest to również wartość podana dla stałej ACCOUNT_TYPE we fragmencie kodu w sekcji Add the Account required by the Framework.
Atrybuty ustawień
android:userVisible
Ustawia widoczność typu konta adaptera synchronizacji. Domyślnie ikona i etykieta konta powiązane z typem konta są widoczne w sekcji Konta w systemowej aplikacji Ustawienia. Dlatego adapter synchronizacji musisz ustawić jako niewidoczny, chyba że masz konto lub domenę, które można łatwo powiązać z aplikacją. Jeśli ustawisz typ konta jako niewidoczny, nadal możesz zezwolić użytkownikom na sterowanie adapterem synchronizacji za pomocą interfejsu użytkownika w ramach jednej z czynności wykonywanych w aplikacji.
android:supportsUploading
Umożliwia przesyłanie danych do chmury. Ustaw go na false, jeśli aplikacja tylko pobiera dane.
android:allowParallelSyncs
Umożliwia jednoczesne uruchamianie wielu instancji komponentu adaptera synchronizacji. Użyj tej opcji, jeśli Twoja aplikacja obsługuje wiele kont użytkowników i chcesz umożliwić wielu użytkownikom równoległe przenoszenie danych. Ta flaga nie będzie działać, jeśli nigdy nie uruchamiasz wielu transferów danych.
android:isAlwaysSyncable
Wskazuje platformę adaptera synchronizacji, że może ona w dowolnym momencie uruchomić adapter synchronizacji. Jeśli chcesz automatycznie kontrolować, kiedy adapter synchronizacji ma działać, ustaw tę flagę na false, a następnie wywołaj requestSync(), aby uruchomić adapter synchronizacji. Więcej informacji o używaniu adaptera synchronizacji znajdziesz w lekcji Uruchamianie adaptera synchronizacji.

Poniższy przykład przedstawia kod XML adaptera synchronizacji, który korzysta z jednego konta zastępczego i tylko do pobierania plików.

<?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"/>

Zadeklaruj adapter synchronizacji w pliku manifestu

Po dodaniu do aplikacji komponentu adaptera synchronizacji musisz poprosić o uprawnienia związane z jego używaniem oraz zadeklarować dodany komponent Service.

Komponent adaptera synchronizacji uruchamia kod, który przesyła dane między siecią a urządzeniem, więc musisz poprosić o dostęp do internetu. Aplikacja musi też prosić o uprawnienia do odczytu i zapisywania ustawień adaptera synchronizacji, aby można było automatycznie sterować adapterem synchronizacji z innych komponentów aplikacji. Musisz też poprosić o specjalne uprawnienie, które pozwoli aplikacji na użycie komponentu uwierzytelniającego utworzonego przez Ciebie w ramach lekcji Tworzenie Stub Authenticator.

Aby poprosić o te uprawnienia, dodaj do manifestu aplikacji jako elementy podrzędne <manifest>:

android.permission.INTERNET
Zezwala kodowi adaptera synchronizacji na dostęp do internetu, aby mógł pobrać dane z urządzenia lub przesłać je na serwer. Nie musisz ponownie dodawać tego uprawnienia, jeśli prosiłeś o nie wcześniej.
android.permission.READ_SYNC_SETTINGS
Umożliwia aplikacji odczyt bieżących ustawień adaptera synchronizacji. Potrzebujesz tego uprawnienia na przykład, aby wywołać funkcję getIsSyncable().
android.permission.WRITE_SYNC_SETTINGS
Umożliwia aplikacji kontrolowanie ustawień adaptera synchronizacji. Potrzebujesz tych uprawnień, aby ustawić okresowe uruchamianie adaptera synchronizacji za pomocą addPeriodicSync(). To uprawnienie nie jest wymagane do wywoływania funkcji requestSync(). Więcej informacji o używaniu adaptera synchronizacji znajdziesz w artykule Uruchamianie adaptera synchronizacji.

Ten fragment kodu pokazuje, jak dodać uprawnienia:

<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>

Aby na koniec zadeklarować granicę Service, której platforma używa do interakcji z adapterem synchronizacji, dodaj ten kod XML do pliku manifestu aplikacji jako element podrzędny <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>

Element <intent-filter> konfiguruje filtr, który jest aktywowany przez działanie intencji android.content.SyncAdapter wysłane przez system w celu uruchomienia adaptera synchronizacji. Po uruchomieniu filtra system uruchamia utworzoną przez Ciebie usługę powiązaną – w tym przykładzie jest to SyncService. Atrybut android:exported="false" umożliwia dostęp do elementu Service tylko aplikacji i systemowi. Atrybut android:process=":sync" informuje system, że ma uruchomić Service w globalnym udostępnionym procesie o nazwie sync. Jeśli w aplikacji masz wiele adapterów synchronizacji, mogą oni korzystać z tego procesu, co zmniejsza nakład pracy.

Element <meta-data> zawiera nazwę utworzonego wcześniej pliku XML metadanych adaptera synchronizacji. Atrybut android:name wskazuje, że te metadane dotyczą platformy adaptera synchronizacji. Element android:resource określa nazwę pliku metadanych.

Masz już wszystkie komponenty adaptera synchronizacji. Z kolejnej lekcji dowiesz się, jak skonfigurować platformę adaptera synchronizacji, aby uruchamiała adapter synchronizacji w odpowiedzi na zdarzenia lub regularnie.