Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

2.15. ContentProvider の発展

Keishin Yokomaku edited this page Feb 26, 2014 · 23 revisions

この章では、ContentProvider の発展的な使用について解説します。

参考:Content Provider Basics | Android Developers
参考:Transferring Data Using Sync Adapter | Android Developers

目次

  • [ContentProvider へのアクセス](#ContentProvider へのアクセス)
    • バッチ処理
    • Intent によるアクセス
  • データの同期
    • 同期の仕組みを使用する準備
    • AbstractThreadedSyncAdapter
    • Service
    • メタデータの宣言
    • AndroidManifest の宣言
    • 同期の実行と下位互換

ContentProvider へのアクセス

ContentProvider へのアクセスは、ContentResolver を介して行うことは、2.10. データベースにて解説しました。このページの方法では、1 回のアクセスで 1 回の操作(挿入、更新、削除)を行うように動作します。

今回は、1 回のアクセスで複数の操作(挿入、更新、削除)を行う、バッチ処理について解説するとともに、ContentResolver 以外の手段を用いた ContentProvider へのアクセスについて解説します。

バッチ処理

ContentProviderOperation に、挿入・更新・削除のいずれかの処理のための情報をもたせ、このオブジェクトを List にまとめて ContentResolver 経由でリクエストすることで、バッチ処理が実行できます。

バッチ処理と同等のリクエストを複数回繰り返すよりも、バッチ処理の方が高速に動作します。一方で、バッチ処理はそのままではアトミック性を保証しないまま動作してしまうため、必要であればContentProvider#applyBatch(ArrayList)をオーバライドして、トランザクションを自分で開始・終了する必要があります。

Intent によるアクセス

データの同期

しばしば、アプリケーションはサーバサイドとのデータのやり取りを密接にやりとりします。ネットワークにつながらない場所に居ても、最低限、それ以前にサーバからダウンロードしておいたデータへのアクセス性を確保したり、定期的にアプリケーション内に蓄積したデータをサーバへ送信することでバックアップを取ったりするような仕組みは、ネットワークへの接続が必ずしも常にあるとは限らない環境において、また、多様な端末を複数使用する環境においては、とても大切な仕組みとなります。

Android では、これらを支援する仕組みとして、クラウドとの同期のためのフレームワークを提供しています。今回は、特に ContentProvider を用いたフレームワークに注目して解説します。

ContentProvider 以外にも同期の仕組みが存在しますが、この仕組は3.08. クラウド同期で解説します。

同期の仕組みを使用する準備

ContentProvider を用いたデータの同期をするには、Authenticator の使用が必要となります。既に Authenticator によるアカウント管理の仕組みがある場合は特に作業の必要はありませんが、アカウント管理の仕組みが必要でないアプリケーションでは、スタブの Authenticator を用意する必要があります。

以下がスタブの Authenticator の実装の例です。アカウント管理をしないのであれば、ロジックを記述せず、操作がサポートされない旨を表すUnsupportedOperationExceptionをスローするようにします。

public class StubAuthenticator extends AbstractAccountAuthenticator {
    public StubAuthenticator(Context context) {
        super(context);
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
        return null; // アカウント管理をしないため、null を返す
    }

    @Override
    public abstract Bundle confirmCredentials (AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
        return null; // アカウント生成の了承リクエストは無視するため、null を返す
    }

    @Override
    public abstract Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
        throw new UnsupportedOperationException("edit properties not supported"); // アカウント情報の編集は、アカウント管理をしないポリシーとなるので例外とする
    }

    @Override
    public abstract Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetowrkErrorException {
        throw new UnsupportedOperationException("get auth token not supported"); // トークン管理も、アカウント管理をしないため例外
    }

    @Override
    public abstract String getAuthTokenLabel(String authTokenType) {
        throw new UnsupportedOperationException("get auth token label not supported"); // トークン管理をしないので、トークンの種類に対応する表示も例外
    }

    @Override
    public abstract Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
        throw new UnsupportedOperationException("feature check not supported"); // アカウント管理をしないため例外
    }

    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse r, Account account, String s, Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException(); // アカウント管理をしないため例外
    }
}

AbstractThreadedSyncAdapter

ContentProvider のデータの同期を目的としたクラスで、ContentResolver によって同期のタイミングが管理されます。

このクラスは、アプリケーションプロセスが実行中、ワーカスレッド上でクラウドとの同期処理を記述するフレームワークを提供しています。UI スレッドとは別のスレッド上で実行される為、各種の IO を同期的に記述しても問題ありません。

public MySyncAdapter extends AbstractThreadedSyncAdapter {
    public MySyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
    }
    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {

    }
}

Service

データの同期のタイミングで呼び出され、AbstractThreadedSyncAdapter に記述した同期の手続きを実行するための Service を定義します。

AbstractThreadedSyncAdapter のインスタンスは、アプリケーションのライフサイクルの中で Singleton として扱うようにし、複数の AbstractThreadedSyncAdapter のインスタンスを生成して並列に同期を実行してしまうことを防ぎます。

public MySyncService extends Service {
    private static AbstractThreadedSyncAdapter sAdapter;
    private static final Object LOCK = new Object();
    @Override
    public void onCreate() {
        synchronized (LOCK) {
            if (sAdapter == null) {
                sAdapter = new MySyncAdapter(getApplicationContext(), true);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return sAdapter.getSyncAdapterBinder();
    }
}

メタデータの宣言

AndroidManifest の宣言

同期の実行と下位互換

GitHub Pagesへ移行しましたmixi-inc.github.ioへお願いします。

Clone this wiki locally