ContentProviderは複数のアプリケーションでデータを共有するための仕組みで、アプリケーション間の連携、効率の観点から共通データタイプ(住所録、画像情報など)を定義しています。
たとえば、スケジュール管理アプリが複数入っている場合、通常なら相互にスケジュールをExport/Importして同期をとる必要がありますが、ContentProviderを介してスケジュールを保存・変更すればどんなスケジュール管理アプリを使っても、常に同期状態を保つことができます。
今回はContentProviderからデータを取得する方法について解説します。ポイントは以下の3つです。
- アプリケーション間でデータを共有するための仕組み
- ContentProviderに格納されているデータはURIで特定
- 格納されているデータ仕様を知っている必要がある(IDやNAME、TYPEなどテーブルのフィールド構造)。
※操作はSQLなどデータベースに近いため、データベースの知識があればより理解しやすいです。
取得の仕方、サンプルコードは続きから。
Content URIについて
コンテントプロバイダのURIは
- content://org.jpn.techbooster.provider/sample/123
のように表現します。これらは以下の4つの要素から構成しています。
- prefix:”content://”固定
- パッケージ名+任意のprovider名:”org.jpn.techbooster.provider”(マニフェストで要素として宣言)
- データ種類:”sample”
- _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を参照してください。