113

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

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

編集-マニフェストスニペットを追加しました私のマニフェストxmlには次のものが含まれています:

<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アダプターxmlと一致します。

ContentResolver.requestSyncは同期を要求する正しい方法ですか?同期テスターツールがサービスに直接バインドし、同期の開始を呼び出すように見えますが、同期アーキテクチャと統合する目的が損なわれているようです。

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

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

4

2 に答える 2

283

呼び出し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>

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

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

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

タグについては<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)し、それが呼び出されたときに a を返さなければなりませんSyncAdapterBinder... type の変数が必要ですAbstractThreadedSyncAdapter。ご覧のとおり、それはそのクラスのほとんどすべてです。それが存在する唯一の理由は、サービスを提供することです。これは、Android が自分SyncAdapter自身が何であるかについてクラスにクエリを実行するための標準インターフェイスを提供します。

3.class SyncAdapter実際に同期を実行するには、 を指定します。

mySyncAdapter は、実際の同期ロジック自体が格納される場所です。そのonPerformSync()メソッドは、同期するときに呼び出されます。あなたはすでにこれを持っていると思います。

4. Account-type と Content Authority の間のバインディングを確立する

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

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

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

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

5. 特定の Account / ContentAuthority ペアで同期を有効にします

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

ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

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

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

また、mgvごとに、requestSync のエクストラ バンドルで true に設定ContentResolver.SYNC_EXTRAS_MANUALすると、グローバル同期がオフの場合でも Android に同期を強制するように求められます (ここではユーザーを尊重してください!)

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

6.複数のアカウントの影響を考慮する

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

7. ContentResolver.notifyChange() に注意する

1 つのトリッキーなこと。ローカル データベースが変更されたことを Android に通知するために sContentResolver.notifyChange()によって使用される関数です。ContentProviderこれは 2 つの機能を果たします。まず、そのコンテンツ uri に続くカーソルを更新し、次に再クエリと無効化と再描画を行いListViewます。これは非常に魔法のようで、データベースが変更され、ListView自動的に更新されます。素晴らしい。また、データベースが変更されると、通常のスケジュール外であっても、Android は同期を要求するため、これらの変更はデバイスから取り除かれ、できるだけ早くサーバーに同期されます。また素晴らしい。

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

8. 幸せを感じよう!

この xml メタデータをすべて配置し、同期を有効にすると、Android はすべてを接続する方法を認識し、同期が機能し始めます。この時点で、多くの優れたものが所定の位置に収まり、まるで魔法のように感じられます。楽しみ!

于 2011-03-10T04:09:54.520 に答える