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
等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章