Androidコンテンツプロバイダー のドキュメント)は、getContentResolver()
から取得したContentResolver
を使用してコンテンツにアクセスする方法を説明しています。
ただし、getContentResolver().acquireContentProviderClient(authority)
から取得できるContentProviderClient
もあります。プロバイダーからのコンテンツにアクセスするためにContentResolver
で利用できるのとほぼ同じメソッドを提供しているようです。
ContentProviderClient
を直接使用するのではなく、ContentResolver
をいつ使用すればよいですか?メリットは何ですか?
あなたのAndroidデバイスには多くのデータベースがあり、各データベースは一意のコンテンツ機関によって識別されます。これはcontent:// uriの「ドメイン名」に相当する部分です-最初のスラッシュの前のすべて。
ContentResolver
は、_String contentAuthority
_からContentProvider
へのマッピングを提供するデータを格納します。 ContentResolver.query()
またはupdate()
またはあなたが持っているものを呼び出すと、URIはそのコンポーネントに分解され、contentAuthority文字列が識別されます。contentResolverは一致する文字列をそのマップで検索する必要があります。クエリを適切なプロバイダーに送信します。 URIは呼び出しごとに異なる場合があり、異なるcontentAuthorityも含まれるため、この高価な検索は呼び出しごとに行われます。さらに、その特定のプロバイダーへの接続のセットアップと切断に関連するコストが発生する可能性があります-呼び出し間で再利用することはできません。そこに含まれるオーバーヘッドはわかりませんが、これはかなり深いOSレベルのコードです。
対照的に、acquireContentProviderClient(authority)
を呼び出すと、「必要なプロバイダーは何ですか?」ルックアップは1回行われ、ContentProviderClient
が与えられます。これは、基本的にContentProvider
への直接リンクです。 (あなたとプロバイダーの間には、スレッド間通信と並行処理ロックを含む少しの接着剤があります)。ただし、ContentProviderClient
を使用すると、要求した権限についてプロバイダーに直接話しかけます。これにより、「どのプロバイダーが必要ですか?」を常に再計算する無駄がなくなります。
注:Per acquireContentProviderClient()documentation :ContentProviderClientを取得する場合、 "呼び出し元は ContentProviderClient.release() を呼び出して、プロバイダーとのやり取りが完了したことを示します。これにより、システムがプロバイダーを解放できるようになり、それをアクティブに保つ他の理由がないと判断されます。 "したがって、基本的に、古いクライアントを開いたままにすると、プロバイダーはバックグラウンドでサービスとして実行し続ける必要があります。だから、クリーンアップすることを忘れないでください!
まとめ:
さまざまなcontentAuthoritiesへの多くの呼び出し:ContentResolver
を使用します。
同じ機関への繰り返しの呼び出し:ContentProviderClient
を取得して使用します。完了したら、必ずrelease()してください。
わかりましたが、アクティビティと同じプロセスでContentProviderが実行されている場合にのみ機能することに注意してください。
メソッドgetLocalContentProvider()
のドキュメントからのメモ:
ContentProviderが別のプロセスで実行されている場合、nullが返されます。これは、プロバイダーと同じプロセスで実行していて、その実装の詳細に直接アクセスしたい場合に使用できます。
もう1つのインポートの違いは、ContentProviderClientをカスタムプロバイダーオブジェクトにキャストして、CRUD以外のメソッドにアクセスできることです。
ContentProvider cp = getContentResolver().acquireContentProviderClient(mCurUri).getLocalContentProvider();
yourProvider fld = (yourProvider)cp;
fld.query(...); // you can query as ContentResolver
fld.addFolder(newFolder); // also can invoke the extend method of your custom ContentProvider
次の違いが見つかりました:アプリAで独自のカスタムコンテンツプロバイダーを作成しました。アプリBでホームスクリーンウィジェットを作成しました。ウィジェットからContentResolverを介してアプリAのContentProviderにアクセスしようとすると、「プロバイダーの検索に失敗しました情報」エラー。代わりに、ContentResolverを介してContentProviderClientを取得し、ContentProviderClientを介してクエリを実行すると、機能します。私は何も変更する必要はありませんでした。ContentResolverの代わりにContentProviderClientを使用するだけです。私はその振る舞いについての本当の説明がなく、なぜそれがそのようなものであるかについて、インターネット上で情報を見つけられませんでした。これがウィジェットの特別な癖であるかどうかはわかりません。アプリBのアクティビティから試したわけではないためです(アプリBは単なるウィジェットであり、アクティビティはありません)。
ContentProviderClientの使用法の1つは、テストでContentProviderのいくつかのメソッドにアクセスするのに役立ちます。たとえば、ユニットテストで shutdown() メソッドを使用して、複数のコンテンツプロバイダーをインスタンス化する複数のテストを回避しています。
次のようにContentProvider#shutdown()
を実装します。
_@Override
public void shutdown() {
openHelper.close();
super.shutdown();
}
_
そして、テストメソッドの最後で、ContentProviderClient
を使用してshutdown()
を呼び出し、テストをクリーンアップして、他のテストがコンテンツプロバイダーを使用できるようにします。
_getContext()
.getContentResolver()
.acquireContentProviderClient(URI)
.getLocalContentProvider()
.shutdown();
_