ContentProviderの一例


回転:
http://book.51cto.com/art/200908/142708.htm
9.3 ContentProvider
データをアプリケーション間で共有する必要がある場合、データとしてContentProviderを利用してURIを定義することができます.その後、他のアプリケーションでデータを検索したり、修正したりする場合は、現在のコンテキストオブジェクトからContentResolaver(コンテンツ解析器)を取得して、対応するURIを入力すればいいです.本セクションでは、前に作成したコード.dbデータベースを例に、どのようにContentProviderを定義するか、他のプログラムでContentResolaverを使ってURIで指定されたデータにアクセスするかを読者に紹介します.
9.3.1 ContentProviderを定義する(1)
現在のアプリケーションのプライベートデータのためにURIを定義するには、ContentProviderから継承されるクラスを特定し、その後、異なる操作によって呼び出す方法でこれらの方法の機能を実現する必要があります.次にSQLite 2という例を用いて、そのデータベースコード.dbのためにURIを定義します.
まず、SQLite 2のカバンの中に新しいクラスのContryCode.javaを作成して、データベース操作に関する静的なフィールドを全部ロードします.JARファイルに包装して、他のアプリケーションの呼び出しのために使います.
1 package com.studio.android.chp9.ex3;  
2  
3 import android.net.Uri;  
4  
5 public class CountryCode {  
6  
7 public static final String DB_NAME = "code.db";  
8 public static final String TB_NAME = "countrycode";  
9 public static final int VERSION = 1;  
10  
11 public static final String ID = "_id";  
12 public static final String COUNTRY = "country";  
13 public static final String CODE = "code";  
14  
15 public static final String AUTHORITY =  
16 "com.studio.andriod.provider.countrycode";  
17 public static final int ITEM = 1;  
18 public static final int ITEM_ID = 2;  
19  
20 public static final String CONTENT_TYPE =  
21 "vnd.android.cursor.dir/vnd.studio.android.countrycode";  
22 public static final String CONTENT_ITEM_TYPE =  
23 "vnd.android.cursor.item/vnd.studio.android.countrycode";  
24  
25 public static final Uri CONTENT_URI =  
26 Uri.parse("content://" + AUTHORITY + "/item");  
27 }
そのうちDB_NAME、TB_NAMEとVERIONはそれぞれデータベースとテーブルの名前とデータベースのバージョン番号を定義しています.ID、COUNTRY、CODEはそれぞれテーブル内の各列の列名を定義しています.AUTHORITYはContentProviderを識別する文字列を定義しています.ITEMとITEM_IDは、それぞれUriMatch(リソース識別子マッチング器)における経路itemとitem/idのマッチング番号に使用される.CONTENT_TYPEとCONTENT_ITEM_TYPEはデータのMIMEタイプを定義しています.なお、単一データのMIMEタイプ文字列は、vnd.android.cursor.item/で始まるべきであり、データセットのMIMEタイプ文字列は、vnd.android.cursor.dir/で始まるべきである.CONTENT_URIは現在のテーブルデータを調べるcontent:/スタイルURIを定義します.
次に、同じSQLite 2のカバンの中にContentProviderから継承された種類のMyProvider.javaを作成して、データ操作の様々な方法を実現する.ここではMyHelperを使ってSQLiteDatabaseオブジェクトを獲得するのを支援します.直接にContactext.OpenOrCreate()方法を使ってもいいですが、データベースを使って補助クラスを開くのは間に合わないです.
public class MyProvider extends ContentProvider {  
MyHelper dbHelper;  
private static final UriMatcher sMatcher;  
static {  
sMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
sMatcher.addURI(CountryCode.AUTHORITY,  
"item",CountryCode.ITEM);  
sMatcher.addURI(CountryCode.AUTHORITY,  
"item/#", CountryCode.ITEM_ID);  
}  
...  
} 
ここでUriMatchタイプの静的フィールドはContentProviderに入ってくるUriに合うクラスです.その構成方法によって導入されたマッチコードは、ルートパスにマッチするためにmatch()法を使用して戻ってくる値であり、このマッチコードは、ゼロより大きい数でマッチルートまたは着信-1を表すことができ、すなわち、定数UriMatch.NO_MATCHは、ルートパスと一致しないことを示している.addURI()方法は他のURI整合経路を追加するために用いられ、最初のパラメータはContentProviderを識別するAUTHORITY文字列に入る.第二のパラメータの着信には、適合する経路が必要であり、ここではどの数字にマッチするかを表し、また、任意のテキストに*を用いてもよい.第3のパラメータは、マッチしたURIに対応するマッチコードを返すために、ゼロより大きいマッチコードを導入しなければならない.
ContentProviderでは、データの各種操作に対して6つの抽象的な方法を定義しています.
@Override  
public boolean onCreate() {  
dbHelper = new MyHelper(getContext(), CountryCode.DB_NAME,  
null,CountryCode.VERSION);  
return true;  
} 
ContentProviderが起動するたびに、OneCreate()方法をフィードバックします.この方法は主にいくつかのContentProvider初期化の作業を行い、trueに戻って初期化に成功し、falseに戻ると初期化に失敗します.このContentProviderでは、主にデータベースを操作する必要がある補助類のオブジェクトを構成しています.
@Override  
public String getType(Uri uri) {  
switch (sMatcher.match(uri)) {  
case CountryCode.ITEM:  
return CountryCode.CONTENT_TYPE;  
case CountryCode.ITEM_ID:  
return CountryCode.CONTENT_ITEM_TYPE;  
default:  
throw new IllegalArgumentException("Unknown URI " + uri);  
}  
} 
getTyper()は、データを返すためのMIMEタイプの方法です.sMatchを使ってURIをマッチングして、対応するMIMEタイプ文字列を返します.もし入ってきたURIにマッチできないなら、IllgalAgmentExceptionを投げます.
@Override  
public int delete(Uri uri, String where, String[] args) {  
SQLiteDatabase db = dbHelper.getWritableDatabase();  
int count;  
switch (sMatcher.match(uri)) {  
case CountryCode.ITEM:  
count = db.delete(CountryCode.TB_NAME, where,args);  
break;  
case CountryCode.ITEM_ID:  
String id = uri.getPathSegments().get(1);  
count = db.delete(CountryCode.TB_NAME, CountryCode.ID + "=" + id  
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), args);  
break;  
default:  
throw new IllegalArgumentException("Unknown URI " + uri);  
}  
getContext().getContentResolver().notifyChange(uri, null);  
return count;  
}  
@Override  
public int update(Uri uri, ContentValues values,  
String where, String[] args) {  
SQLiteDatabase db = dbHelper.getWritableDatabase();  
int count;  
switch (sMatcher.match(uri)) {  
case CountryCode.ITEM:  
count = db.update(CountryCode.TB_NAME,values, where,args);  
break;  
case CountryCode.ITEM_ID:  
String id = uri.getPathSegments().get(1);  
count = db.update(CountryCode.TB_NAME,values,CountryCode.ID+"=" + id  
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), args);  
break;  
default:  
throw new IllegalArgumentException("Unknown URI " + uri);  
}  
getContext().getContentResolver().notifyChange(uri, null);  
return count;  
} 
delete()とudate()の方法はそれぞれデータの削除と修正操作に用いられ、影響データの数を返します.私たちのところの二つの方法の実現は比較的似ている.まず、データベース支援オブジェクトを利用してSQLiteDatabaseオブジェクトを取得します.次に、SQLiteDatabaseオブジェクトの削除または変更方法を呼び出したときに、where文に異なる表現を使用するために、導入されたUriに従ってsMatchをマッチングさせ、単一のデータまたはデータセットを削除または修正する.ここではget Contect()メソッドを呼び出すContectオブジェクトを取得し、このContectオブジェクトを利用してContect Resoliverのオブジェクトを取得します.notifyChange()メソッドは、このURIに登録されている観察者にデータが変更されたことを通知するために使用されます.最後に、データの削除または変更の行数を返します.
@Override  
public Uri insert(Uri uri, ContentValues initialValues) {  
SQLiteDatabase db = dbHelper.getWritableDatabase();  
long rowId;  
if (sMatcher.match(uri) != CountryCode.ITEM) {  
throw new IllegalArgumentException("Unknown URI " + uri);  
}  
rowId =  
db.insert(CountryCode.TB_NAME,CountryCode.ID,initialValues);  
if (rowId > 0) {  
Uri noteUri =  
ContentUris.withAppendedId(CountryCode.CONTENT_URI, rowId);  
getContext().getContentResolver().notifyChange(noteUri, null);  
return noteUri;  
}  
throw new SQLException("Failed to insert row into " + uri);  
} 
insert()メソッドはデータを挿入し、最後に新たに挿入されたデータのURIを返します.この方法の実現においては、データセットのURIのみを受け入れる.すなわちテーブルのURIを指す.そして、データベース支援オブジェクトで得られたSQLiteDatabaseオブジェクトを利用して、insert()メソッドを呼び出して指定テーブルにデータを挿入します.最後に観察者にデータの変化を通知し、挿入データのURIを返します.
@Override  
public Cursor query(Uri uri, String[] projection,  
String selection, String[] args,String order) {  
SQLiteDatabase db = dbHelper.getReadableDatabase();  
Cursor c;  
switch (sMatcher.match(uri)) {  
case CountryCode.ITEM:  
c = db.query(CountryCode.TB_NAME, projection, selection,  
args,null,null,order);  
break;  
case CountryCode.ITEM_ID:  
String id = uri.getPathSegments().get(1);  
c = db.query(CountryCode.TB_NAME, projection, CountryCode.ID + "="  
+ id  
+ (!TextUtils.isEmpty(selection)  
? " AND (" + selection + ')' : ""),  
args,null,null,order);  
break;  
default:  
throw new IllegalArgumentException("Unknown URI " + uri);  
}  
c.setNotificationUri(getContext().getContentResolver(), uri);  
return c;  
} 
query()はデータを照会する方法であり、最終的に照会の結果をCursorオブジェクトにパッケージして返す.その実装は、まず、データベース支援オブジェクトを通じてSQLiteDatabaseオブジェクトを取得し、次にsMatchを使用して着信URIをマッチングし、単一データと複数データのURI構造が異なるwhere文式を作成して照会する.set NotificationUri()方法は、Cursorオブジェクトのために観測データの変化を登録するURIである.
これらの抽象的な方法を実現した後、完全なContentProviderが定義されました.残りはAndroid d-Manifest.xmlの中でこのContentProviderに対する声明です.Android Manifest.xmlには以下のような声明コードが追加されています.
<provider android:name=「MyProvider」
android:authorities=「comp.studio.andriod.provider.co untrycode」
その中で、android:nameは先ほどContentProvider類を定義したクラス名に設定する必要があります.android:authoritiesはcontent:/スタイルのURIにこのContentProviderの文字列を指定しました.また、Android:readPermissionとandroid:writePermissionの2つの属性を設定して、このContentProviderにおけるデータの読み書き操作に関する権限をそれぞれ指定することができます.オンクリアー()方法の実装において、set Read-Paermission()とsetWritePermission()方法を呼び出して、権限を動的に指定することもできる.
他のプログラムをより便利に使用するために、私たちが定義したContentProviderは、一般的に使用する静的データをJARアーカイブファイルにエクスポートします.本プログラムで使用する静的フィールドはすべてCountryCodeに配置されています.以下はJARファイルに梱包する手順です.
(1)プロジェクトフォルダ上またはCountryCode.javaファイル上で右クリックし、Exportを選択します.
(2)ポップアップの選択エクスポートタイプのダイアログでJAR fileを選択し、次のxtをクリックします.
(3)エクスポートするファイルボックスを選択するには、CountryCode.javaのみが選択されます.Browse...ボタンを見つけて、エクスポートパス(デフォルトはworkspace)を指定し、Finishを選んでCountryCode.jarをエクスポートします.
JARファイルをエクスポートした後、他のアプリケーションで使用する必要があれば、そのプロジェクトのために外部のアーカイブファイルを追加すればいいです.このプロジェクトフォルダの右ボタンでBuild path→Add External Archiveを見つけ、図9-5に示すように、追加するJARファイルを選択すると、プログラムの中でimport文を使ってアーカイブファイルの内容を導入することができます.
自動回転
http://blog.chinaunix.net/u3/90973/showart_2161195.
コンテントプロバイダーはいつ作成されましたか?誰が作成しましたか?アプリケーション共有のデータにアクセスするには、このアプリケーションを起動しますか?この問題はAndroid SDKでは明確に説明されていませんが、データ共有の観点から、ContentProviderはAndroidでシステム起動時に作成されたはずです.でないと、データ共有とは言えません.これは、Android Manifest.XMLで元素を使って明確に定義することが要求されます.
複数のプログラムが同時にContentResoloverを通じてContentProviderを訪問することができますが、データベースのような「汚いデータ」をもたらすことができますか?この問題は、データベースアクセスの同期、特にデータ書き込みの同期が必要であり、Android Manifest.XMLでContentProviderを定義する場合、要素multiprocess属性の値を考慮する必要がある.一方、AndroidはContentResolaverにnotifyChangeインターフェースを提供しています.データの変更時に他のContentObserverに通知します.ここでは観察者モードを使用しています.ContentReslaverにはregister、unregisterのようなインターフェースがあります.
これまでContentProviderに対して比較的全面的な分析を提供してきましたが、どのようにContentProviderを作成するかについては、2つの方法があります.あなた自身のContentProviderを作成するか、または既存のContit Providerにデータを追加するかはもちろん前提としています.Android SDKのsampleで提供される
添付ファイルは自分で書いたテスト例です.