1. 程式人生 > >Android四大元件之ContentProvider

Android四大元件之ContentProvider

關於ContentProvider

ContentProvider,被稱為內容提供者,通過Binder向其他元件以及其他應用提供資料。以某種Uri的形式對外提供資料,允許其他應用訪問或修改資料。其他應用程式使用ContentResolver根據Uri去訪問操作指定資料。ContentProvider主要以表格的形勢組織資料,有行列的層次性。另外還支援圖片,視訊等。

建立ContentProvider

  • 自定義ContentProvider,該類繼承ContentProvider,實現六個必須需要實現的抽象方法
public class MyContentProvider extents ContentProvider{
/* * 建立時被呼叫 */ @Override public boolean onCreate(){ return false} /* * 根據Uri查詢符合selection條件的全部記錄,projection是一個列名列表,選擇出指定的資料列,有點sql的select的意思 */ @Override public Cursor query(Uri uri,String[] project,String selection,String[] selectionArgs,String sortOrder){ //一般使用SQLiteDatabase進行資料的增刪查改
return null; } /* * 返回Uri查詢出的selection條件的資料的MIME型別 */ @Override public String getType(Uri uri){ //當對應多條記錄時 以vnd.android.cursor.dir/開頭 //當對應單條記錄時 以vnd.android.cursor.item/開頭 return null; } /* * 根據Uri插入對應的value的資料 */ @Override public Uri insert(Uri uri,ContentValues values){ return null; }
/* * 根據Uri刪除selection匹配的記錄 */ @Override public int delete(Uri uri,String selection,String[] selectionArgs){ return 0} /* * 根據Uri修改selection匹配的記錄 */ @Override public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){ return 0} }
  • 在AndroidManifest中註冊該ContentProvider
<provider
	android:name=".MyContentProvider"
	android:authorities="com.xxxx.xxx.MyContentProvider" //唯一標識,通過它外部應用訪問MyContentProvider
	android:exported="true" // 屬性用於指示該服務是否能夠被其他應用程式元件呼叫或跟它互動。如果設定為true,則能夠被呼叫或互動,否則不能
	android:multiprocess="true" //為true時:多例項 false:單例項
	/> 

還有一些其他屬性
readPermission:使用Content Provider的查詢功能所必需的許可權,即使用ContentProvider裡的query()函式的許可權;
writePermission:使用ContentProvider的修改功能所必須的許可權,即使用ContentProvider的insert()、update()、delete()函式的許可權;
permission:客戶端讀、寫 Content Provider 中的資料所必需的許可權名稱。readPermission和writePermission屬性優先於本設定。 如果同時設定了readPermission屬性,則其將控制對 Content Provider 的讀取。 如果設定了writePermission屬性,則其也將控制對 Content Provider 資料的修改。也就是說如果只設置permission許可權,那麼擁有這個許可權的應用就可以實現對這裡的ContentProvider進行讀寫;如果同時設定了permission和readPermission那麼具有readPermission許可權的應用才可以讀,擁有permission許可權的才能寫!也就是說只擁有permission許可權是不能讀的,因為readPermission的優先順序要高於permission;如果同時設定了readPermission、writePermission、permission那麼permission就無效了。

	android:permission="com.xxx.myPermission"  
    android:readPermission="com.xxx.myPermission.read"  
    android:writePermission="com.xxx.myPermission.write"

Uri組成

如: content://com.xxx.xxx.myContentProvider/hello 分為三部分

  • content:// :類似網路協議的http://
  • com.xxx.xxx.myContentProvider:是指在AndroidManifest中authorities屬性,由該部分找到操作的ContentProvider
  • hello:資源部分,訪問不同的資源,動態改變

ContentResolver操作資料

首先ContentResolver到底是什麼,由上面描述可知,ContentProvide的作用是用來暴露資料,而ContentResolver就是用來操作資料
在這裡插入圖片描述
由關係圖可以看出,當應用A想要對B的資料進行增刪查改時,就需要通過ContentResolver來實現。而ContentResolver通過Context提供的 getContentResolver方法獲取。然後通過呼叫ContentResolver的CRUD方法操作資料

  • query(Uri uri,String[] project,String selection,String[] selectionArgs,String sortOrder):當應用A呼叫該方法時,相當於呼叫了Uri指向的ContentProvider的query方法
  • insert(Uri uri,ContentValues values)
  • delete(Uri uri,String selection,String[] selectionArgs)
  • public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)

首先來舉例 查詢 例項:

引數 型別 對應SQL部分 描述
uri Uri from table_name 查詢某個應用程式指定表
projection String[] select column1,column2 指定查詢列名
selection String where column = value where中約束條件
selectionArgs String[] 為where中的佔位符提供具體的值
orderBy String order by columns1,column2 指定排序方式
//將內容字串解析成Uri物件
Uri uri = Uri.parse("content://com.xxx.xxx.myContentProvider/hello");
Cursor cursor = getContentResolver().query(uri,project,selection,selectionArgs,sortOrder);
if(cursor!=null){
	while(cursor.moveToNext()){
		String colum1 =cursor.getString(cursor.getColumnIndex("column1"));
		int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
	}
	cursor.close();
}

新增

ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);

修改

ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1=? and column2 = ?",new String[]{"text","1"});
//使用selection和selectionArgs對想要更新的資料進行約束

刪除

getContentResolver().delete(uri,values,"column2=?",new String[]{"1"});
//使用selection和selectionArgs對想要更新的資料進行約束

讀取系統ContentProvider

下面展示在實際開發中如何讀取系統的聯絡人。

private void readContacts(){
	Cursor cursor = null;
	try{
		//查詢聯絡人資料
		cursor = getContentResolver().query(
			ContactsContract.commonDataKinds.Phone.CONTENT_URI,
			null,null,null,null);
		while(cursor.moveToNext()){
			//獲取聯絡人姓名
			String Name=cursor.getString(
				cursor.getColumnIndex(ContactContract.CommonDataKinds.Phone.DISPLAY_NAME));
			//儲存姓名操作
			//獲取聯絡人手機號碼
			String number = cursor.getString(
				cursor.getColumnIndex(ContactContract.CommonDataKinds.Phone.NUMBER));
			//儲存手機號碼操作
		}
	}catch(Exception e){
		e.printStackTrace();
	}finally{
		if(cursor!=null){
			cursor.close();
		}
	}
}

監聽ContentProvider資料變化

  • 操作者
    在操作ContentResolver時,通過呼叫
getContext().getContentResolver().notifyChange(uri,null);

會通知註冊在該Uri的監聽者,該ContentProvider上的資料發生了變化

  • 觀察者
    要監聽指定Uri的ContentProvider的資料變化,需要利用ContentObserver。註冊程式碼如下
/**
*	Uri 指定uri
*	notifyForDescendents :boolean型別,true時,子路徑的資料改變也會通知,false:當前路徑才通知
*	MyObserver 繼承ContentObserver,當所監聽資料變化,呼叫onChange()
*/
getContentResolver().registerContentObserver(uri,true,new MyObserver(new Handler()));

//自定義匿名內部監聽類
private final class MyObserver extends ContentObserver{
	public MyObserver(Handler handler){
		super(handler);
	}
	public void onChange(boolean selfChange){
		//當資料改變時執行相應操作
	}
} 

資料