Android四大元件-ContentProvider
概念:
內容提供器,Android 四大元件之一。
作用:
可以操作非本應用程式的資料,實現跨程序資料共享。
優點:
可以在保證資料的安全性的情況下實現資料跨程序共享。因為contentprovider規範了統一的資料訪問介面。
對底層資料儲存方式抽象,即如果您將底層資料儲存方式修改對資料應用層不會有影響。
原理:
底層實現原理是Binder機制,Binder實現原理是通過Binder類,實現IBinder介面。Binder機制原理是:Binder驅動在核心空間建立一塊資料快取區,並呼叫系統mmap()方法實現記憶體對映,傳送程序呼叫系統方法傳送資料到虛擬記憶體區域,由於核心快取區和接收程序空間地址存在對映關係,所以也就相當於傳送到了接收程序的使用者空間地址,實現了跨程序通訊。 傳送程序(client)和接收程序(server)通過ServiceManager與Binder驅動溝通。
用法:
- 通過contentresolver進行增刪改查操作。使用contentresolver的原因:可以統一管理provider
- 通過URI表示需要獲取資料的表名,uri的固定形式:content://Authority/path/id
- Authority:授權資訊,用以區別不同的contentprovider。
- path:表名,用以區分contentprovider的不同的資料表。
- ID:id號,用以區別表中不同的資料。
- UriMatchar:固定格式,單條記錄:vnd.android.cursor.item/自定義,多條記錄:vnd.android.cursor.dir/自定義
用法示例1:
讀取手機中的通訊錄資訊,涉及執行時許可權申請詳見官方文件:https://developer.android.com/training/permissions/requesting?hl=zh-cn
//讀取通訊錄主要邏輯程式碼 private void readContact(){ Cursor cursor = null; try{ //獲取contentresolver ContentResolver resolver = context.getContentResolver(); // //查詢通訊錄的資料 cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null); //遍歷資料獲取具體欄位 if (cursor!=null){ while (cursor.moveToNext()){ String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); contcacts.add(name+"\n"+number); } adapter = new ArrayAdapter(mActivity, android.R.layout.simple_list_item_activated_1, contcacts); lv.setAdapter(adapter); } }catch(Exception e){ e.printStackTrace(); }finally{ if(cursor!=null){ cursor.close(); } } }
用法示例2:
實現跨程序資料共享。步驟如下:
-
建立好資料庫
-
在程序A中建立Provider,注意需要註冊,並且設定可以對外。
-
在provider中定義好UriMatcher和authorty(與B程序通訊的連結)。
-
實現6大方法。
-
在B程序通過上下文獲取contentresolver,通過resolver對A程序資料庫程序增刪改查操作。
程序A:建立一個繼承ContentProvider的類,並實現重寫的方法。
**注:**示例中的UserDao是封裝的一個對sqlite資料庫增刪改查的操作的類。具體可詳見github上的demo。https://github.com/MarinaTsang/sqliteAndContentprovider/tree/master/app
/**
* 實現跨程序資料共享
*/
public class MyProvider extends ContentProvider {
//自定義的urimatcher 中的自定義程式碼
private static final int TABLE1_DIR = 0;
private static final int TABLE1_ITEM = 1;
//自定義uri規則
private static final String AUTHORITY = "com.example.zeng.contentprovider.provider";
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, MySqlHelper.TABLE_NAME,TABLE1_DIR);
uriMatcher.addURI(AUTHORITY,MySqlHelper.TABLE_NAME+"/#",TABLE1_ITEM);
}
private UserDao userDao;
/**
* 初始化 內容提供器 ,此方法內一般進行資料庫的建立和升級操作。 執行在content
* provider的主執行緒中,故不能做耗時操作。
* @return true ---初始化成功 false---初始化失敗
*/
@Override
public boolean onCreate() {
userDao = new UserDao(getContext());
return true;
}
/**
* 查詢
* @param uri uri,固定格式,用於標識讀取哪裡的資料
* @param projection 需要查詢的列的陣列,null表示所有列
* @param selection 需要過濾的條件 where語句,null返回所有行
* @param selectionArgs where的引數
* @param sortOrder 對結果進行排序
* @return
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
Cursor cursor= null;
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
//查詢表1 所有資料
cursor = userDao.query(projection, selection, selectionArgs, sortOrder);
break;
case TABLE1_ITEM:
//查詢表1 單條資料
String queryId = uri.getPathSegments().get(1);
cursor = userDao.query(projection,"uid= ?",new String[]{queryId},sortOrder);
break;
}
return cursor;
}
/**
* uri是內容解析者傳遞過來的:contentresolver
* 根據傳入的URI來返回對應的 MIME型別, 兩種型別:vnd.android.cursor.item/ 單條記錄, uri 以ID結尾 vnd.android.cursor.dir/ 多條記錄
* @return
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd."+AUTHORITY+"."+MySqlHelper.TABLE_NAME;
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd."+AUTHORITY+"."+MySqlHelper.TABLE_NAME;
}
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
Uri uriRetrun = null;
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
case TABLE1_ITEM:
long l = userDao.addDatasWithValues(values);
uriRetrun = Uri.parse("content://"+AUTHORITY+"/"+MySqlHelper.TABLE_NAME+"/"+l);
}
return uriRetrun;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return userDao.deleteData(selection,selectionArgs);
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return userDao.updateDataWithVaules(values,selection,selectionArgs);
}
}
程序B使用contentresolver獲取資料:
用法與用法示例1 獲取手機通訊錄方法一致。
完整demo地址:https://github.com/MarinaTsang/sqliteAndContentprovider
參考文章:
https://www.jianshu.com/p/06309249f2a0
https://developer.android.com/reference/android/content/ContentProvider
等。