web-dev-qa-db-ja.com

ContentResolver.requestSyncが同期をトリガーしないのはなぜですか?

Google IO -スライド26で説明されているように、Content-Provider-Syncアダプターパターンを実装しようとしています。コンテンツプロバイダーは機能しており、Dev Tools Sync Testerアプリケーションからトリガーすると同期が機能します、ただし、ContentProviderからContentResolver.requestSync(account、authority、bundle)を呼び出すと、同期がトリガーされません。

ContentResolver.requestSync(
        account, 
        AUTHORITY, 
        new Bundle());

編集-マニフェストスニペットを追加しました

<service
    Android:name=".sync.SyncService"
    Android:exported="true">
    <intent-filter>
        <action
            Android:name="Android.content.SyncAdapter" />
    </intent-filter>
    <meta-data Android:name="Android.content.SyncAdapter"
    Android:resource="@xml/syncadapter" />
</service>

-編集

同期サービスに関連付けられたsyncadapter.xmlには次のものが含まれます。

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:Android="http://schemas.Android.com/apk/res/Android"  
    Android:contentAuthority="AUTHORITY"
    Android:accountType="myaccounttype"
    Android:supportsUploading="true"
/>

他のどのコードが役立つかわからない。 requestSyncに渡されたアカウントは「myaccounttype」であり、呼び出しに渡されたAUTHORITYはsyc adapter xmlと一致します。

ContentResolver.requestSyncは同期をリクエストする正しい方法ですか?同期テスターツールはサービスに直接バインドし、start syncを呼び出すように見えますが、同期アーキテクチャと統合する目的に反しているようです。

それが同期を要求する正しい方法である場合、なぜ同期テスターは機能しますが、ContentResolver.requestSyncの呼び出しは機能しませんか?バンドルで渡す必要があるものはありますか?

2.1および2.2を実行しているデバイスのエミュレーターでテストしています。

111
Ben

requestSync()の呼び出しは、システムに認識されている{Account、ContentAuthority}ペアでのみ機能します。アプリは、特定の種類のアカウントを使用して特定の種類のコンテンツを同期できることをAndroidに伝えるためにいくつかの手順を実行する必要があります。 AndroidManifestでこれを行います。

1。アプリケーションパッケージが同期を提供することをAndroidに通知します

まず、AndroidManifest.xmlで、同期サービスがあることを宣言する必要があります。

_<service Android:name=".sync.mySyncService" Android:exported="true">
   <intent-filter>
      <action Android:name="Android.content.SyncAdapter" /> 
    </intent-filter>
    <meta-data 
        Android:name="Android.content.SyncAdapter" 
        Android:resource="@xml/sync_myapp" /> 
</service>
_

_<service>_タグのname属性は、同期を接続するためのクラスの名前です...これについてはすぐに説明します。

Exportをtrueに設定すると、他のコンポーネントから見えるようになります(ContentResolverが呼び出せるようにするために必要です)。

インテントフィルターを使用すると、同期を要求するインテントをキャッチできます。 (このIntentは、ContentResolver.requestSync()または関連するスケジューリングメソッドを呼び出すときにContentResolverから取得されます。)

_<meta-data>_タグについては後述します。

2。 SyncAdapterの検索に使用するサービスをAndroidに提供します

クラス自体...ここに例があります:

_public class mySyncService extends Service {

    private static mySyncAdapter mSyncAdapter = null;

    public SyncService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (mSyncAdapter == null) {
            mSyncAdapter = new mySyncAdapter(getApplicationContext(), true);
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return mSyncAdapter.getSyncAdapterBinder();
    }
}
_

クラスはServiceまたはそのサブクラスの1つを拡張し、public IBinder onBind(Intent)を実装し、呼び出されたときにSyncAdapterBinderを返す必要があります...タイプAbstractThreadedSyncAdapterの変数が必要です。ご覧のとおり、これがそのクラスのほとんどすべてです。唯一の理由は、AndroidにSyncAdapter自体が何であるかをクラスに照会するための標準インターフェースを提供するサービスを提供することです。

3。 _class SyncAdapter_を指定して、実際に同期を実行します。

mySyncAdapterは、実際の同期ロジック自体が保存される場所です。 onPerformSync()メソッドは、同期するときに呼び出されます。すでにこれが用意されていると思います。

4。アカウントタイプとコンテンツオーソリティの間のバインディングを確立します

AndroidManifestをもう一度振り返ると、このサービスの奇妙な_<meta-data>_タグは、ContentAuthorityとアカウント間のバインディングを確立する重要な要素です。外部で別のxmlファイルを参照します(好きな名前、アプリに関連するものを呼び出します)。sync_myapp.xmlを見てみましょう。

_<?xml version="1.0" encoding="utf-8" ?> 
<sync-adapter 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"   
    Android:contentAuthority="com.Android.contacts"
    Android:accountType="com.google" 
    Android:userVisible="true" /> 
_

さて、これは何をしますか? Androidに、定義した同期アダプター(このファイルを参照する_<service>_タグを含む_<meta-data>_タグのname要素で呼び出されたクラス)を伝えます。 ..)com.googleスタイルのアカウントを使用して連絡先を同期します。

すべてのcontentAuthority文字列はすべて一致する必要があり、同期対象と一致する必要があります-独自のデータベースを作成する場合はこれを定義する文字列にする必要があります。同期する場合は既存のデバイス文字列を使用する必要がありますデータタイプ(連絡先、カレンダーイベント、またはあなたが持っているものなど)上記(「com.Android.contacts」)は、連絡先タイプデータ(サプライズ、サプライズ)のContentAuthority文字列です。

accountTypeは、既に入力されている既知のアカウントタイプの1つと一致するか、作成中のアカウントタイプと一致する必要があります(これには、アカウント認証を取得するためのAccountAuthenticatorのサブクラスの作成が含まれます...記事自体の価値があります)。繰り返しになりますが、「com.google」は... google.comスタイルのアカウント認証情報を識別する定義済みの文字列です(これも驚くべきことではありません)。

5。特定のアカウント/ ContentAuthorityペアで同期を有効にします

最後に、同期を有効にする必要があります。これを行うには、コントロールパネルの[アカウントと同期]ページでアプリに移動し、一致するアカウント内のアプリの横にあるチェックボックスを設定します。または、アプリのセットアップコードでそれを行うことができます。

_ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
_

同期を行うには、アカウント/権限のペアを同期できるようにし(上記のように)システムの全体的なグローバル同期フラグを設定する必要がありますおよびデバイスにはネットワーク接続が必要です。

アカウント/権限の同期またはグローバル同期が無効になっている場合、RequestSync()を呼び出すと効果があります。同期が要求されたことを示すフラグが設定され、同期が有効になるとすぐに実行されます。

また、 mgv ごとに、requestSyncのextrasバンドルで_ContentResolver.SYNC_EXTRAS_MANUAL_をtrueに設定すると、グローバル同期がオフの場合でも同期を強制するようAndroidに要求されます(ここにあなたのユーザー!)

最後に、ContentResolver関数を使用して、定期的なスケジュールされた同期をセットアップできます。

6。複数のアカウントの意味を考慮してください

同じタイプのアカウントを複数持つことができます(1つのデバイスに2つの@ gmail.comアカウント、2つのFacebookアカウント、または2つのTwitterアカウントなどを設定します)。それを行うことのアプリケーションへの影響を考慮する必要があります。 .. 2つのアカウントがある場合は、おそらく両方を同じデータベーステーブルに同期しようとは思わないでしょう。一度にアクティブにできるのは1つだけで、アカウントを切り替える場合はテーブルをフラッシュして再同期する必要があるかもしれません。 (存在するアカウントを照会するプロパティページを使用)。アカウントごとに異なるデータベースを作成したり、異なるテーブルを作成したり、各テーブルのキー列を作成したりできます。すべてのアプリケーション固有であり、いくつかの考えに値します。 ContentResolver.setIsSyncable(Account account, String authority, int syncable)はここで興味深いかもしれません。 setSyncAutomatically()は、アカウント/権限ペアがcheckeduncheckedかを制御しますが、setIsSyncable()は、ユーザーがオンにできないように、行をオフにしてグレー表示する方法を提供します。 1つのアカウントをSyncableに設定し、もう1つのアカウントをSyncable(dsabled)に設定しないでください。

7。 ContentResolver.notifyChange()に注意してください

1つ注意が必要です。 ContentResolver.notifyChange()は、Androidにローカルデータベースが変更されたことを通知するためにContentProvidersが使用する関数です。これは2つの機能を提供します。最初に、そのコンテンツuriに続くカーソルを更新し、次にListViewなどを再クエリおよび無効化して再描画します。これは非常に魔法で、データベースが変更され、ListViewが自動的に更新されます。驚くばかり。また、データベースが変更されると、Androidは、通常のスケジュール外でもSyncを要求します。これにより、これらの変更がデバイスから削除され、サーバーにできるだけ迅速に同期されます。また素晴らしい。

ただし、エッジケースが1つあります。サーバーからプルし、ContentProviderに更新をプッシュすると、notifyChange()とAndroidが忠実に呼び出され、「データベースの変更、サーバーに配置した方が良い! 」 (Doh!)よく書かれたContentProvidersには、変更がネットワークから来たのかユーザーから来たのかを確認するテストがあり、もしそうであれば、この無駄な二重同期を防ぐためにブール値syncToNetworkフラグをfalseに設定します。 ContentProviderにデータを供給する場合、これを機能させる方法を理解する必要があります-そうしないと、1つだけが必要なときに常に2つの同期を実行することになります。

8。幸せを感じてください!

このxmlメタデータをすべて配置し、同期を有効にすると、Androidがすべてを接続する方法を認識し、同期が機能し始めるはずです。この時点で、ナイスなものの多くはクリックするだけで、まるで魔法のように感じられます。楽しい!

279
jcwenger