同期アダプターを作成する

注: WorkManager をおすすめします。 バックグラウンド処理のほとんどのユースケースで推奨されるソリューションです。詳しくは、 バックグラウンド処理ガイドをご覧ください。

アプリ内の同期アダプター コンポーネントは、転送するタスクのコードをカプセル化します。 デバイスとサーバー間で 送受信されるデータです指定したスケジュールとトリガーに基づいて 同期アダプター フレームワークが同期アダプター コンポーネント内のコードを実行します。コメントを追加するには、 同期アダプター コンポーネントをアプリに追加するには、次の要素を追加する必要があります。

同期アダプター クラス。
同期アダプターと互換性のあるインターフェースでデータ転送コードをラップするクラス。 説明します。
バインドされている Service
同期アダプター フレームワークが同期アダプター内のコードを実行できるようにするコンポーネント クラスです。
同期アダプターの XML メタデータ ファイル。
同期アダプターに関する情報を含むファイル。フレームワークはこのファイルを読み取って、 データ転送を読み込んでスケジュールする方法を ご覧ください
アプリ マニフェスト内の宣言。
バインドされたサービスを宣言し、同期アダプター固有のメタデータを参照する XML。

このレッスンでは、これらの要素を定義する方法について説明します。

同期アダプター クラスを作成する

このレッスンのこのパートでは、 あります。クラスの作成には、同期アダプターの基本クラスの拡張、 クラスのコンストラクタと、データ転送を定義するメソッドの実装 できます。

基本同期アダプター クラスを拡張する

同期アダプター コンポーネントを作成するには、まず、 AbstractThreadedSyncAdapter とそのコンストラクタを記述する。こちらの 同期アダプター コンポーネントが作成されるたびに設定タスクを実行するよう構成します。 Activity.onCreate() を使用して Compute Engine インスタンスを できます。たとえば、アプリがコンテンツ プロバイダを使用してデータを保存している場合は、 ContentResolver インスタンスを取得します。2 番目の形式の コンストラクタが Android プラットフォーム バージョン 3.0 で追加され、parallelSyncs をサポートしました。 互換性を維持するため、2 つの形式のコンストラクタを作成する必要があります。

注: 同期アダプター フレームワークは、同期アダプターと連携するように設計されています。 コンポーネントが含まれます。同期アダプター コンポーネントのインスタンス化については、 後ほど詳しく説明します。 同期アダプターをフレームワークにバインドします

次の例は、Cloud Functions の関数を実装する方法を示しています。 AbstractThreadedSyncAdapter とそのコンストラクタ:

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

データ転送コードを追加する

同期アダプター コンポーネントでは、データ転送は自動的には行われません。代わりに、 はデータ転送コードをカプセル化して、同期アダプター フレームワークが アプリは関与せずにバックグラウンドでデータ転送を行えます。フレームワークの準備ができたら アプリケーションのデータを同期するには、メソッドの実装が呼び出されます。 onPerformSync()

メインのアプリコードから同期アダプター コンポーネントへのデータ転送を容易にするために、 同期アダプター フレームワークは、 onPerformSync() は、 次の引数を使用します。

アカウント
トリガーしたイベントに関連付けられた Account オブジェクト 同期アダプターを使用します。サーバーでアカウントを使用していない場合は、 このオブジェクトの情報を取得します。
エクストラ
同期をトリガーしたイベントによって送信されたフラグを含む Bundle 設定してください。
権限
システム内のコンテンツ プロバイダの権限。アプリは 関連付けられています通常、オーソリティは自身のアプリ内のコンテンツ プロバイダに対応します。
で確認できます。
コンテンツ プロバイダ クライアント
がポイントするコンテンツ プロバイダの ContentProviderClient あります。ContentProviderClient は、Pod 内で実行される コンテンツ プロバイダへのインターフェースを提供します。基本的な機能は ContentResolver。コンテンツ プロバイダを使用してデータを保存している場合 このオブジェクトを使用してプロバイダに接続できます。それ以外の場合は、無視してかまいません。 できます。
同期結果
同期に情報を送信するために使用する SyncResult オブジェクト 説明します。

次のスニペットは、BigQuery の 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.
     */
}

アプリの実際の実装は onPerformSync() は次固有です: サーバー接続プロトコルなど、いくつかの種類があります。 一般的なタスクについて説明します。

サーバーへの接続
データ転送の開始時にネットワークが利用可能であると想定できますが、 同期アダプター フレームワークはサーバーに自動的に接続しません。
データのダウンロードとアップロード
同期アダプターはデータ転送タスクを自動化しません。1 対 1 のチャットを コンテンツ プロバイダに保存する場合は、そのコードをコンテンツ プロバイダに がデータをリクエストしてダウンロードし、プロバイダに挿入します。同様に サーバーにデータを送信するには、ファイル、データベース、プロバイダからデータを読み取り、 自動的に作成します。また、接続中に発生するネットワーク エラーへの対処も データを転送できます
データ競合の処理やデータの新しさの判断
同期アダプターはサーバー上のデータとデータの競合を自動的に処理しない 確認できます。また、サーバー上のデータが またはその逆に変更できます。代わりに、トレーニング データに基づいた独自のアルゴリズムを この状況に対処できます
クリーンアップする。
サーバーへの接続を常に閉じ、終了時に一時ファイルとキャッシュをクリーンアップする データの移行が遅れます

注: 同期アダプター フレームワークは、 onPerformSync(): 独自のバックグラウンド処理を設定する必要はありません。

同期関連のタスクに加えて、通常のタスクを組み合わせて タスクを作成し、それを VM に onPerformSync()。 すべてのネットワーク タスクをこのメソッドに集中させることで、 ネットワークインターフェースの起動と停止に必要な ネットワークインターフェースを提供しますネットワーク アクセスの仕組みについて 効率的に作業するには、トレーニング クラス「Transferring Data without バッテリーを消耗させる」をご参照ください。このトレーニング クラスでは、複数のネットワーク アクセスについて説明しています。 いくつか紹介します。

同期アダプターをフレームワークにバインドする

データ転送コードは同期アダプター コンポーネントにカプセル化されましたが、 フレームワークからコードにアクセスできるようになります。そのためには、Cloud Storage バケットを Service: 同期アダプターから特別な Android バインダー オブジェクトを渡す フレームワークに組み込みます。フレームワークはこのバインダー オブジェクトを使用して、 onPerformSync() メソッドと データを渡します。

同期アダプター コンポーネントを サービスの onCreate() メソッド。インスタンス化 onCreate() のコンポーネントでは、 サービスが開始するまで作成する必要があります。これは、フレームワークが最初にアプリケーションを実行しようとしたときに行われます。 転送できます。同期処理が失敗したときは、コンポーネントをスレッドセーフな方法でインスタンス化する必要があります。 トリガーまたはトリガーに応答して、同期アダプターの複数の実行をキューに入れる できます。

たとえば、次のスニペットは、この関数を実装するクラスの作成方法を示しています。 バインドされた Service が、同期アダプター コンポーネントをインスタンス化して、 Android のバインダー オブジェクト:

Kotlin

package com.example.android.syncadapter
/**
 * Define a Service that returns an [android.os.IBinder] for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
class SyncService : Service() {
    /*
     * Instantiate the sync adapter object.
     */
    override fun onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized(sSyncAdapterLock) {
            sSyncAdapter = sSyncAdapter ?: SyncAdapter(applicationContext, true)
        }
    }

    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    override fun onBind(intent: Intent): IBinder {
        /*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         *
         * We should never be in a position where this is called before
         * onCreate() so the exception should never be thrown
         */
        return sSyncAdapter?.syncAdapterBinder ?: throw IllegalStateException()
    }

    companion object {
        // Storage for an instance of the sync adapter
        private var sSyncAdapter: SyncAdapter? = null
        // Object to use as a thread-safe lock
        private val sSyncAdapterLock = Any()
    }
}

Java

package com.example.android.syncadapter;
/**
 * Define a Service that returns an <code><a href="/reference/android/os/IBinder.html">IBinder</a></code> for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
public class SyncService extends Service {
    // Storage for an instance of the sync adapter
    private static SyncAdapter sSyncAdapter = null;
    // Object to use as a thread-safe lock
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Instantiate the sync adapter object.
     */
    @Override
    public void onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
            }
        }
    }
    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    @Override
    public IBinder onBind(Intent intent) {
        /*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         */
        return sSyncAdapter.getSyncAdapterBinder();
    }
}

注: 同期アダプターのバインドされたサービスのより詳細な例を確認するには、 サンプルアプリをご覧ください。

フレームワークで必要なアカウントを追加する

同期アダプター フレームワークでは、各同期アダプターにアカウントの種類が必要です。宣言しました アカウントの [アカウントの種類] に 認証システムのメタデータ ファイルを追加します。次に、このアカウントの種類を Android システム。口座種別を設定するには、口座種別を使用するプレースホルダ アカウントを追加します addAccountExplicitly() を呼び出します。

メソッドを呼び出す最適な場所は、 onCreate() メソッド( オープニング アクティビティです。次のコード スニペットは、その方法を示しています。

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

同期アダプターのメタデータ ファイルを追加する

フレームワークに同期アダプター コンポーネントを接続するには、フレームワークを提供する必要があります。 コンポーネントを記述し、追加のフラグを指定するメタデータを含む。metadata では、 同期アダプター用に作成したアカウント タイプ、コンテンツ プロバイダ オーソリティを宣言する 同期アダプターに関連するシステム ユーザー インターフェースの一部を制御します。 同期関連の他のフラグを宣言します。このメタデータは、ファイル システムに格納されている特別な XML ファイルで宣言し、 アプリ プロジェクトの /res/xml/ ディレクトリ。ファイルには任意の名前を付けることができます。 ただし、通常は syncadapter.xml と呼ばれます。

この XML ファイルには、<sync-adapter> 次のような属性があります。

android:contentAuthority
コンテンツ プロバイダの URI 認証局。スタブ コンテンツ プロバイダを作成した場合は、 前のレッスンのスタブ コンテンツ プロバイダを作成するでアプリに 属性 android:authorities (アプリ マニフェストに追加した <provider> 要素)で呼び出します。この属性は、 後のセクションで詳しく説明します。 マニフェストでプロバイダを宣言します。
同期アダプターを使用してコンテンツ プロバイダからサーバーにデータを転送する場合は、 の値は、そのデータに使用しているコンテンツ URI オーソリティと同じにする必要があります。この値 で指定する権限の 1 つでもある android:authorities アプリ マニフェストでプロバイダを宣言する <provider> 要素の属性を使用します。
android:accountType
同期アダプター フレームワークで必要なアカウントの種類。同じ値にする必要があります。 認証情報メタデータ ファイルの作成時に指定したアカウント タイプの値( 認証システムのメタデータ ファイルを追加するをご覧ください。また、 セクションのコード スニペットの定数 ACCOUNT_TYPE フレームワークに必要なアカウントを追加します
設定属性
android:userVisible
同期アダプターのアカウントの種類の公開設定を設定します。デフォルトでは、 アカウント タイプに関連付けられたアカウント アイコンとラベルが、 システムの設定アプリの [アカウント] セクション(同期を行う必要があります) 簡単に関連付けられるアカウントの種類またはドメインがある場合を除いて、アダプタは表示されません。 説明しますアカウントの種類を非表示にした場合でも、 アプリのアクティビティのユーザー インターフェースで同期アダプターを制御する。
android:supportsUploading
データをクラウドにアップロードできる。アプリのみの場合は、false に設定します。 ダウンロードします。
android:allowParallelSyncs
同期アダプター コンポーネントの複数のインスタンスを同時に実行できます。 アプリが複数のユーザー アカウントをサポートしており、 データを並行して転送できますterraform plan または terraform apply を 複数のデータ転送に対応できます
android:isAlwaysSyncable
いつでも同期アダプターを実行できることを同期アダプター フレームワークに示します。 表示されます。同期のタイミングをプログラムで制御したい場合は、 このフラグを false に設定して、次の呼び出しを行います。 requestSync() を実行して、 同期アダプターを使用します。同期アダプターの実行について詳しくは、このモジュールの 同期アダプターの実行
をご覧ください。
をご覧ください。

次の例は、単一のプレースホルダ アカウントを使用する同期アダプターの XML を示しています。 ダウンロードのみを行います。

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

マニフェストで同期アダプターを宣言する

同期アダプター コンポーネントをアプリに追加したら、権限をリクエストする必要があります。 コンポーネントの使用に関連するため、バインドされた Service を宣言する必要があります。 表示されます。

同期アダプター コンポーネントは、ネットワークと インターネットにアクセスする権限をリクエストする必要があります。さらに、アプリには 同期アダプターの設定に対する読み取り / 書き込み権限をリクエストして、同期を管理できるようにする アプリ内の他のコンポーネントからプログラムで統合できます。さらに、 作成した認証システム コンポーネントをアプリが使用できるようにする特別な権限 スタブ認証システムの作成をご覧ください。

これらの権限をリクエストするには、アプリの子要素として以下をアプリ マニフェストに追加します。 <manifest>:

android.permission.INTERNET
同期アダプターのコードがインターネットにアクセスして、データをダウンロードまたはアップロードできるようにします デバイスからサーバーに送ります。以下の場合は、この権限を再度追加する必要はありません。 必要があります。
android.permission.READ_SYNC_SETTINGS
現在の同期アダプター設定の読み取りをアプリに許可します。たとえば、 getIsSyncable() を呼び出すには権限が必要です。
android.permission.WRITE_SYNC_SETTINGS
同期アダプター設定の制御をアプリに許可します。以下の操作を行うには、この権限が必要です。 addPeriodicSync() を使用して、同期アダプターの定期的な実行を設定する。この権限は、次の呼び出しに必要ありませんrequestSync()。詳細情報 同期アダプターの実行をご覧ください。

次のスニペットは、権限を追加する方法を示しています。

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

最後に、フレームワークが使用するバインドされた Service を宣言します。 同期アダプターを操作する場合は、次の XML を子要素としてアプリ マニフェストに追加します。 /<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>

<intent-filter> 要素は、インテントのアクションによってトリガーされるフィルタを設定します android.content.SyncAdapter: 同期アダプターを実行するためにシステムによって送信されます。フィルタ トリガーされると、作成したバインドされたサービス(この例では SyncService。属性 android:exported="false" アプリとシステムのみが Service。属性 android:process=":sync" というグローバル共有プロセス内で Service を実行するようシステムに指示します。 sync。アプリに複数の同期アダプターがある場合、それらのアダプターはこのプロセスを共有できます。 オーバーヘッドを削減できます

<meta-data> 要素には、前に作成した同期アダプター メタデータ XML ファイルの名前を指定します。 「 android:name 属性は、このメタデータが同期アダプター フレームワーク用であることを示します。「 android:resource 要素には、メタデータ ファイルの名前を指定します。

これで、同期アダプターのすべてのコンポーネントが揃いました。次のレッスンでは、 イベントに応答して、またはイベントに応答して、同期アダプター フレームワークを実行するよう同期アダプター フレームワークに指示します 作成することもできます。