ContentProviderからデータを取得する


AndroidのフレームワークにはContentProvider(コンテントプロバイダ)と呼ばれるデータを保存/取得できる機能が備わっています。データ管理をアプリケーションごとに行うと、データ交換や相互のフォーマット変換がとても煩雑になります。

ContentProviderは複数のアプリケーションでデータを共有するための仕組みで、アプリケーション間の連携、効率の観点から共通データタイプ(住所録、画像情報など)を定義しています。

たとえば、スケジュール管理アプリが複数入っている場合、通常なら相互にスケジュールをExport/Importして同期をとる必要がありますが、ContentProviderを介してスケジュールを保存・変更すればどんなスケジュール管理アプリを使っても、常に同期状態を保つことができます。

今回はContentProviderからデータを取得する方法について解説します。ポイントは以下の3つです。

  • アプリケーション間でデータを共有するための仕組み
  • ContentProviderに格納されているデータはURIで特定
  • 格納されているデータ仕様を知っている必要がある(IDやNAME、TYPEなどテーブルのフィールド構造)。

※操作はSQLなどデータベースに近いため、データベースの知識があればより理解しやすいです。

取得の仕方、サンプルコードは続きから。

Content URIについて

コンテントプロバイダのURIは

  • content://org.jpn.techbooster.provider/sample/123

のように表現します。これらは以下の4つの要素から構成しています。

  1. prefix:”content://”固定
  2. パッケージ名+任意のprovider名:”org.jpn.techbooster.provider”(マニフェストで要素として宣言)
  3. データ種類:”sample”
  4. _IDで定義されているID:”123″

よく使う共通のデータ構造はContactsContract.CommonDataKindsクラスとして、まとめられています。
ContactsContract.CommonDataKinds(Android Developers)

データ構造例(連絡先)

具体的には、連絡先情報は以下のような要素を持っています

_ID _COUNT NAME NUMBER
44 3 Alan Vain 212 555 1234
13 3 Bully Pulpit 425 555 6677
53 3 Rex Cars 201 555 4433

※_IDは必須要素です。要素が多いため一部のみを掲載しています。
連絡先の場合、CommonDataKinds.Phontとして以下のとおり用意されています。

  • _ID:ContactsContract.CommonDataKinds.Phone._ID
  • _COUNT:ContactsContract.CommonDataKinds.Phone._COUNT
  • 表示名:ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
  • 電話番号:ContactsContract.CommonDataKinds.Phone.NUMBER

ContentURIとこれらデータ構造の要素を組み合わせてContentProviderから任意の情報を取得します。

連絡先(Contacts)から名前を取得する

連絡先にアクセスするにはパーミッション設定が必要です。事前にAndroidManifest.xmlに”android.permission.READ_CONTACTS”を追加してください。
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="org.jpn.techbooster.sample.ContentProviderActivity"
      android:versionCode="1"
      android:versionName="1.0">
   <uses-permission android:name="android.permission.READ_CONTACTS" />
   <application android:icon="@drawable/icon" android:label="@string/app_name">
...省略...

サンプルコード

レコードを取得する

先頭の連絡先情報、連絡先レコード(レコード≒データ単位)を取得するサンプルです。

        //クエリ(データを取り出すための操作)を作る
        Cursor cursor = managedQuery(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        //カーソルを移動(レコードの先頭に)
        cursor.moveToFirst();

        int fieldIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
        Long id = cursor.getLong( fieldIndex );
        //カーソルを閉じる
        cursor.close();

クエリを生成してCursor cursorオブジェクトで操作します。
6行目 Cursor#getColumnIndexメソッドでPhone._IDのインデックスを取得します。
7行目 Cursor#getLongメソッドで先頭レコードの_IDの値を取得しています。
これで先頭の連絡先情報のIDがわかりました。IDを鍵に、同じレコードに保存されているNAME(名前)を取得します。

名前を取得する

IDから名前を取得します。2行目、5行目(コメントアウト)に記載していますが、URIの作成方法はいくつか存在しています(ContentUris or Uriを使う)

        //ContentUrisメソッドを使ってベースとなるURIとIDから該当レコードのUriを生成します
        Uri person = ContentUris.withAppendedId(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, id);

        //引数の与え方が異なりますがUriメソッドを使っても同様のことが可能です
        //Uri person = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, String.valueOf(id) );

        //レコードを取得するクエリ、カーソル作成
        cursor = managedQuery(person, null, null, null, null);

        //ContentsResolverを利用してカーソルを取得する方法
        //cursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ id, null, null);

        cursor.moveToFirst();

        //フィールド名を取り出す。今回は名前がdisplay_nameのカラムのインデックスを取得。
        String displayName = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;
        fieldIndex = cursor.getColumnIndex(displayName);

        //先頭IDのユーザー名を取得
        String name = cursor.getString(fieldIndex);
        cursor.close();

        TextView tv = (TextView)findViewById(R.id.username);
        tv.setText(name);

サンプルでは、8行目 managedQueryメソッドでクエリを生成したあと17行目 DISPLAY_NAMEフィールドを探して、名前を取り出しています。
クエリ生成については11行目のように ContentResolver を使うこともできます。サンプルでは先頭IDの連絡先を取得して名前を表示しました。

先頭以外の特定のデータを取得したい場合、8行目のmanagedQueryメソッドの第2引数以降、SQLに似た条件式を追加する必要があります。
詳細は http://developer.android.com/guide/topics/providers/content-providers.html のMaking the queryを確認してください。

※注意:Android DevelopersのMaking the query 記載サンプルで使われているandroid.provider.Contacts.Peopleは非推奨APIになっていました。サンプルが多少古いようです。必要に併せて代替のContactsContract.Contactsを参照してください。

3 Comments