Android四大組件之內容提供者--ContentProvider,android四大組件
Android四大組件之內容提供者--ContentProvider 1,什麼是ContentProviderContentProvider將應用中的資料對其它應用進行共用, 提供增刪改查的方法ContentProvider統一了資料的訪問方式,不必針對不同資料類型採取不同的存取原則ContentProvider將資料封裝,只暴露出我們希望提供給其它程式的資料ContentProvider中可以註冊觀察者, 監聽資料的變化2,怎麼建立2.1定義類繼承ContentProvider, 實現抽象方法2.2在資訊清單檔中註冊:在資訊清單檔的<application>節點下進行配置<provider>標籤,標籤中需要指定name和authorities屬性name:完整的類名。可以省略包名(manifest節點的package值),注意:省略後的類名是以"."開頭的。authorities:是訪問Provider時的路徑,要唯一3,在手機上註冊將應用安裝到手機上即可, 不用運行程式4,其它應用怎麼訪問外部應用使用ContentResolver類對ContentProvider中的資料進行訪問(CRUD操作)擷取解析器ContentResolverContentResolver resolver = Context.getContentResolver();通過resolver.insert(), delete(), update(), query()方法訪問Uri關聯的ContentProvider5,Uri的處理URI代表要操作的資料,由scheme、authorites、path三部分組成eg:content://com.jxn.provider/personscheme | authorites | path1,schema:表明要訪問ContentProvider。固定為:"content://"2,Authority(主機名稱或授權):定義了是哪個ContentProvider提供這些資料。3,path:路徑,可根據商務邏輯自訂。eg: person、person/insert、person/insert/10等等4,ID:通常定義URI時使用"#"號預留位置代替, 使用時替換成對應的數字"content://com.jxn.provider/person/#" #表示資料id(#代表任一數字)"content://com.jxn.provider/person/*" *來匹配任意文本Android系統提供了兩個用於操作Uri的工具類:UriMatcher 和 ContentUris 1,UriMatcher類用於匹配Uri,用法如下:第一步:把你需要匹配的Uri路徑全部給註冊上,如下://常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);//如果match()方法匹配content://com.jxn.provider.personprovider/person路徑,返回匹配碼為1matcher.addURI("com.jxn.provider.personprovider", "person", 1);//添加需要匹配uri,如果匹配就會返回匹配碼//如果match()方法匹配content://com.jxn.provider.personprovider/person/230路徑,返回匹配碼為2matcher.addURI("com.jxn.provider.personprovider", "person/#", 2);//#號為萬用字元第二步:使用matcher.match(uri)方法對輸入的Uri進行匹配,如果匹配成功就返回匹配碼switch (matcher.match(Uri.parse("content://com.jxn.provider.personprovider/person/10"))) { case 1// 相應的業務操作break;case 2// 相應的業務操作break;default:// 相應的業務操作break;}2,ContentUris類用於為路徑加上ID和擷取路徑的ID給Uri加上id:ContentUris.withAppendedId(uri, id) 擷取id:ContentUris.parseId(uri)6,監聽內容提供者資料變化1,如果ContentProvider的訪問者需要知道ContentProvider中的資料發生了變化,可以在ContentProvider 發生資料變化時調用getContentResolver().notifyChange(uri, null)來通知註冊在此URI上的訪問者,例如:public class PersonContentProvider extends ContentProvider {public Uri insert(Uri uri, ContentValues values) {db.insert("person", "personid", values);// 註:如果沒有調用notifyChange()方法,即使其它應用註冊了ContentObserver,也不會知道ContentProvider中的資料的變化getContext().getContentResolver().notifyChange(uri, null);}}2,如果ContentProvider的訪問者需要得到資料變化通知,必須使用ContentObserver對資料(用uri描述)進行監聽,當監聽到資料變化通知時,系統就會調用ContentObserver的onChange()方法:getContentResolver().registerContentObserver(Uri.parse("content://com.jxn.providers.personprovider/person"),true, new PersonObserver(new Handler()));public class PersonObserver extends ContentObserver{public PersonObserver(Handler handler) {super(handler);}public void onChange(boolean selfChange) {//此處可以進行相應的業務處理}}7,補充getType()方法:主要用於匹配資料類型,返回當前Uri所代表資料的MIME類型。如果返回資料是單條資料:vnd.android.cursor.item 如果返回資料是多條資料:vnd.android.cursor.dir案例:B應用通過A應用提供的ContentProvider訪問A應用中的資料// 提供ContentProvider的A應用中定義的SQLiteProviderpublic class SQLiteProvider extends ContentProvider {// Uri匹配器, 用來匹配傳入的Uriprivate static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);private static final int PERSON = 1;// DBOpenHelper extends SQLiteOpenHelperprivate DBOpenHelper helper;static {// 設定一個Uri, 如果匹配到person, 返回1matcher.addURI("com.jxn.sqlite.provider", "person", PERSON);}// 其它應用第一次訪問時(此時會建立ContentProvider)執行// 第一次啟動時執行, 然後會長期駐留在後台, 除非被殺死, 否則不會再執行@Overridepublic boolean onCreate() {helper = new DBOpenHelper(getContext());return true;}// 外部應用使用此方法查詢資料@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {SQLiteDatabase db = helper.getReadableDatabase();// 用匹配器匹配傳入的uriswitch (matcher.match(uri)) {case PERSON:return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);// 執行查詢default:throw new RuntimeException("Uri不能識別: " + uri);}}// 外部應用使用此方法添加資料@Overridepublic Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db = helper.getWritableDatabase();switch (matcher.match(uri)) {case PERSON:long id = db.insert("person", "id", values);// 插入記錄, 得到idreturn ContentUris.withAppendedId(uri, id);// 把id跟在uri後面返回default:throw new RuntimeException("Uri不能識別: " + uri);}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase db = helper.getWritableDatabase();switch (matcher.match(uri)) {case PERSON:return db.delete("person", selection, selectionArgs);default:throw new RuntimeException("Uri不能識別: " + uri);}}@Overridepublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {SQLiteDatabase db = helper.getWritableDatabase();switch (matcher.match(uri)) {case PERSON:return db.update("person", values, selection, selectionArgs);default:throw new RuntimeException("Uri不能識別: " + uri);}}@Overridepublic String getType(Uri uri) {switch (matcher.match(uri)) {case PERSON:return "vnd.android.cursor.dir/person";// mimetypedefault:throw new RuntimeException("Uri不能識別: " + uri);}}}// B應用中要訪問A應用的資料的測試類別public class ProviderTest extends AndroidTestCase {public void test() {// 擷取解析器對象ContentResolver resolver = getContext().getContentResolver();// 訪問內容提供者Uri uri = Uri.parse("content://com.jxn.sqlite.provider");ContentValues values = new ContentValues();}public void testQuery() {// 擷取解析器對象ContentResolver resolver = getContext().getContentResolver();Uri uri = Uri.parse("content://com.jxn.sqlite.provider/person");// 訪問內容提供者Cursor c = resolver.query(uri, new String[]{ "id", "name", "balance" }, "balance>?", new String[]{ "9000" }, "balance DESC");while (c.moveToNext()) {Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2));System.out.println(p);}}public void testInsert() {ContentResolver resolver = getContext().getContentResolver();Uri uri = Uri.parse("content://com.jxn.sqlite.provider/person");ContentValues values = new ContentValues();values.put("name", "provider");values.put("balance", 12345);// 插入資料, 並且得到這條資料的uriuri = resolver.insert(uri, values);System.out.println(uri);}public void testUpdate() {ContentResolver resolver = getContext().getContentResolver();Uri uri = Uri.parse("content://com.jxn.sqlite.provider/person");ContentValues values = new ContentValues();values.put("name", "update");values.put("balance", 54321);int count = resolver.update(uri, values, null, null);System.out.println(count);}public void testDelete() {ContentResolver resolver = getContext().getContentResolver();Uri uri = Uri.parse("content://com.jxn.sqlite.provider/person");int count = resolver.delete(uri, null, null);System.out.println(count);}public void testGetType() {ContentResolver resolver = getContext().getContentResolver();// 擷取uri的類型String type = resolver.getType(Uri.parse("content://com.jxn.sqlite.provider/person"));System.out.println(type);}}