愚鈍人プログラミングメモJavaAndroidコンテンツプロバイダSQLiteでデータベースAndroidグラフィックス(1)-Viewクラスへの描画プログラミングメモつれづれなるままに...個人的なメモコンテンツプロバイダSQLiteデータベースのデータ等の、アプリケーションが管理しているリソースは、通常は他のアプリケーションから使う事はできません。住所録などのデータを一元的に管理して、いろいろなアプリケーションから利用できると便利です。アプリケーションの管理しているリソースを、他のアプリケーションから利用する事ができます。以前に、「ListViewとListActivity(3)-応用編」の「SimpleCursorAdapterクラス-コンテンツプロパイダよりデータを取得してリスト表示する。ListViewウィジェットに表示する例を紹介しました。コンテンツプロパイダで管理するデータとしてよく扱われるのは、SQLiteデータベースのデータです。コンテンツプロパイダによるデータのアクセス方法も、SQLiteデータベースへのアクセスとよく似ています。コンテンツプロパイダでどのような事ができるのかを説明する前に、実際に自前のコンテンツプロパイダを実装してみます。NotePadProvider.javaのコードが参考になります。人の名前と年令の列からなる簡単なSQLiteのテーブル「person_table」を管理するコンテンツプロパイダを実装してみます。コンテンツプロバイダのデータ定義情報を記述したクラスPersonsを作成します。リスト1-プロパイダ情報定義クラス(Persons.java)コンテンツプロバイダのデータ定義情報を示すクラスには、BaseColumnインターフェースをimplementsします。コンテンツプロバイダのデータには、データ行を識別するためののキーとなる「_id」列が必須です。BaseColumnインターフェースには、「_id」列を示す_ID定数が定義されています。AUTHORITY定数(7行目)は、コンテンツプロバイダを識別するための文字列です。小文字にしたものを使います。CONTENT_URI定数は、コンテンツプロパイダの「person_table」のデータを示す「コンテキストURI」の、Uriオブジェクトを定義しています。コンテンツプロパイダのコンテキストURIについては後述の「コンテントURIとUriMatcher」で説明します。コンテンツプロバイダオブジェクトは、getTypeメソッドでプロバイダのデータタイプを示す文字列を返す必要があります。特定の行を返すことを示すCONTENT_ITEM_TYPE定数を定義しています。(このデータタイプを示す文字列の値は、サンプルプログラムNotePadを参考にして適当に決めましたが、もしかしたら、違う文字列の方が良いのかも?)13行目と14行目のNAME定数とAGE定数は、プロパイダが返すデータの列名を示す文字列を定義しています。次にSQLiteデータベースにアクセスするための、ヘルパークラスを作成します。リスト2-ヘルパークラス(PersonOpenHelper.java)このコードは、「SQLiteでデータベース」のリスト1(1)とほぼ同じものです。変更点としては、テーブルの列名の指定に、リスト1のPersonsクラスで定義した定数を、使っている事です。コンテンツプロパイダクラスの実装コンテンツプロパイダを実装するには、ContentProviderクラスを継承したクラスを作成します。リスト3-コンテンツプロパイダ(PersonProvider.java)クラスのスタティックイニシャライザでの処理25~34行目で、スタティックイニシャライザを使って、静的変数uriMatcherとpersonProjectionMapを初期化しています。静的初期化子」を参照して下さい。uriMatcher変数については、次の「コンテントURIとUriMatcher」で説明します。personProjectionMap変数については、queryメソッドのところで説明します。Identifier)によりツリー構造で管理します。コンテンツプロパイダを操作するには、「コンテンツプロバイダを識別するための文字列」に、データの種類を特定するためのパスを追加した、「コンテントURI」を指定します。リスト3のコンテンツプロパイダPersonProviderの場合は、パスが「/persons」と指定された場合に、対象のデータとしてperson_tableの全行のデータを指定した事になります。_ID列の値が数値と一致する行のみを指定した事になります。保仁」の行のみを指定した事になります。「コンテントURI」は、WebページのURLの指定のしかたと同じです。「コンテントURI」では「content://コンテンツプロバイダを識別するための文字列/データの種類を特定するためのパス」を指定する事になります。「コンテントURI」より、データの種類を特定するためのパスに何が指定されているか判断するには、UriMatcherオブジェクトを使います。addURIメソッドの第1引数には、コンテンツプロバイダを識別するための文字列を指定します。第2引数には、データの種類を示すパスのパターンを指定します。第3引数には、パスがコンテントURIとマッチした時に返される、int型の値を指定します。以下は、リスト3のUriMatcherオブジェクトの定義部分です。28行目のaddURIメソッドの第2引数の「persons/#」は、「persons/数値」とマッチするパスをUriMatcherオブジェクトに登録する事を意味しています。Persons.AUTHORITY定数には、リスト1の7行目で、「gudon.sample.personprovider.personprovider」が代入されています。リスト3の20行目と21行目で、PERSONS定数には1が、PERSON_ID定数には2が代入されています。コンテントURIが、どのパスとマッチしているか調べるには、matchメソッドを使います。matchメソッドの引数には、コンテントURIを指定します。このURIが、addURIメソッドで登録したパスに一致した場合には、addURIメソッドの第3引数で指定した値が返されます。以下は、コンテントURIがどのパスとマッチしているかを判断するためのコードの例です。ContentProviderクラスのメソッドContentProviderクラスを継承したクラスはonCreate.query,insert,update,delete,getTypeの5つのメソッドを実装する必要があります。リスト3の、これらのメソッドの処理をみていきます。インスタンス変数personOpenHelperに代入しているだけです。queryメソッドqueryメソッドは、コンテンツプロパイダに問い合わせ要求があった場合によびだされます。このメソッドで、問い合わせ条件にマッチしたデータを抽出して返します。queryメソッドでは、SQLiteQueryBuilderオブジェクトを生成して、変数qbに代入しています。SQLiteQueryBuilderは、SQLのSELECT文による問い合わせをおこなうためのオブジェクトです。リスト3の46行目のsetTablesメソッドで、問い合わせ対象のテーブル名を指定しています。appendWhereメソッドを使って_id列の値が一致する行のみを抽出しています。ここで、50行目と53行目のsetProjectionMapメソッドは、問い合わせ結果の列を別名にマップするための、列名のペアをHahオブジェクトで指定します。SELECT文でASにより、列名に別名をつけるのに相当します。引数に指定されているpersonProjectionMapには、スタティックイニジャライザで、別名としてもともとの列名と同じ名前を登録しています。(同じ名前を登録しているので、setProjectionMapメソッドは無くてもかまわないのですが、テーブルの列に別名をつける場合のサンプルコードとして、あえて使っています。使い方はSQLiteDatabaseオブジェクトのqueryメソッドとほとんど同じです。64行目のsetNotificationUriメソッドは、コンテンツプロパイダの状態の変更を通知するためのメソッドのようです。サンプルプログラムNotePadProvider.javaのコードで使われていたので、理解できていませんがそのまま入れてあります。insertメソッドinsertメソッドは、コンテンツプロパイダにデータを挿入する時に呼び出されるメソッドです。このメソッドは、ただ単にSQLiteDatabaseオブジェクトのinsertメソッドを間接的に呼び出してます。74~76行目で、ContentValuesオブジェクトに列データが指定されていない場合の処理の例として、「name」列のデータが指定されていない場合に、デフォルトのデータ「詠み人知らず」を指定するようにしています。挿入したデータのUriオブジェクトを作成しています(80~84行目)。サンプルプログラムNotePadProvider.javaのコードで使われていたコードをそのまま入れてあります。updateメソッドコンテンツプロパイダのデータを、更新する時に呼び出されるメソッドです。これも、ただ単に、SQLiteDatabaseオブジェクトのupdateメソッドを、間接的に呼び出しているだけです。_id列の値が一致する行のみを更新するようにしています。deleteメソッドコンテンツプロパイダのデータを、削除する時に呼び出されるメソッドです。これも、ただ単に、SQLiteDatabaseオブジェクトのdeleteメソッドを、間接的に呼び出しているだけです。_id列の値が一致する行を削除するようにしています。getTypeメソッドデータの種類を示す文字列を返します。ここでは、コンテントURIのパスに対応した、リスト1のPersonsクラスで定義されている定数を返しています。アクティビティからコンテンツプロパイダを操作アクティビティから、コンテンツプロパイダを操作するコードを以下に示します。このプログラムは、コンテンツプロパイダ・アプリケーション内のアクティビティでも、他のアプリケーションのアクティビティからでも、同じように動作します。プロバイダの操作」で、説明します。マニュフェストファイルアンドロイドがコンテンツプロパイダを認識するためには、マニュフェストファイルにproviderタグを追加する必要があります。providerタグのname属性には、コンテンツプロパイダのクラス名を指定します。authorities属性には、コンテンツプロバイダを識別するための文字列(リスト1のAUTHORITY定数の値)を指定します。プロバイダの操作リスト4のプログラムを実行すると、以下の図のような画面が表示されます。プロバイダを使うには、ContextオブジェクトのgetContentResolverメソッドを使って、ContentResolverオブジェクトを取得します(リスト4・22行目)。プロバイダを操作します。プロバイダに、データを挿入する場合の例です。憲剛」の、2行のデータを追加しています。プロバイダのデータを更新する場合の例です。ContentUris.withAppendedIdメソッドは、コンテントURIにIDのパスを追加して、変更対象のデータの_ID列を限定しています。圭佑」の年齢を99才に変更しています。プロバイダのデータを削除する場合の例です。保仁」のデータを削除しています。次のdeleteメソッド(50行目)では、_パラメータを使って、年令が29才のデータを削除しています。プロバイダのデータを、Cursorオブジェクトとして取得しています。圭佑」の行のみを、取得する事もできます。プロバイダのqueryメソッド(リスト3・43行目)が呼ばれます。その後、SimpleCursorAdapterを使って、ListViewに取得したCursorオブジェクトのデータを表示しています。ListtViewによるデータの表示については、「「SimpleCursorAdapterクラス-コンテンツプロパイダーよりデータを取得してリスト表示する。最後に、getColumnDataメソッドを実行して、ログに、取得した行の年令データを出力しています。getColumnDataメソッドのコードは、Cursorオブジェクトにより行を走査して、列データを取得する場合のサンプルです。このように、他のアプリケーション内のリソースを自アプリケーションから、SQLiteデータベースのデータを操作するように、手軽に利用する事ができます。