[Android四大組件] ContentProvider 內容提供器

ContentProvider 內容提供器

  • 什麼是內容提供器

    官方解釋:

    A content provider manages access to a central repository of data. A provider is part of an Android application, which often provides its own UI for working with the data. However, content providers are primarily intended to be used by other applications, which access the provider using a provider client object. Together, providers and provider clients offer a consistent, standard interface to data that also handles inter-process communication and secure data access.

    通俗易懂:

    主要是用於不同的應用程序之間實現數據共享的功能.

    內容提供器以一個或多個表(跟數據庫的表類似)的形式呈獻給外部應用.

    分兩類:

    • 使用現有的內容提供器來讀取和操作應用程序的數據

    • 創建自己的內容提供器提供外部訪問接口


  • ContentProvider的基本用法

    • 訪問其他程序的數據

      • ContentResolver類

        如果想要訪問內容提供器中共享的數據, 就需要藉助ContentResolver類, 可以通過Context.getContentResolver()方法來獲取該類的實例.

        這個ContentResolver提供了一些對數據進行CRUD的操作, 也就是常說的”增刪查改”

        但是, 與SQLiteDatabase不同的是, ContentResolver的增刪查改方法是不接受表名參數的,而是 Uri,

        Uri: 由 權限 和 路徑 組成的. (用於在提供程序中標識數據的URI)。

        Uri的標準寫法如下:

        content://com.example.app.provider/table1

        table1爲數據庫的名字;

        再使用Uri.parse(uri) 就可以將字符串轉發爲Uri類型啦.

        說了那麼多,我們還沒開始訪問數據, 代碼如下:

        Cursor cursor=getContentResolver().query(
            uri,
            projection,
            selection,
            selectionArgs,
            sortOrder
        );

        上面傳入參數很多, 下面表格將這些參數和SQLiteDatabase中的query()進行了對比:

        query() 對應SQL部分 描述
        uri from table_name 指定查詢應用程序的某一個表
        projection select column1,column2 指定查詢的列名
        selection where column=value 爲where中的佔位符提供具體的值
        selectionArgs - 爲where的佔位符提供具體的值
        sortOrder order by column1, column2 指定查詢結果的排序方式

        很明顯上面返回的是Cursor類, 讀取數據的思路就是通過移動遊標的位置來遍歷Cursor的所有行, 然後取出每一行相應列的數據, 代碼如下:

        if(cursor!=null){
            while(cursor.moveToNext()){
                String column1 = cursor.getString(cursor.getColumnIndex("column1"));
                int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
            }
            cursor.close();
        }

        以下是各種操作的簡單介紹:

        ContentValues values=new ContentValues();
        
        //插入數據
        getContentResolver().insert(uri, values);
        
        //更新數據
        getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[]{"text","1"});
        
        //刪除數據
        getContentResolver().delete(uri, "column2 = ?", new String[]{"1"});

  • 創建自己的ContentProvider

    • 創建前的準備

      1. 決定你是否需要ContentProvider

        • 你想爲其他應用提供複雜的數據或文件

        • 你想允許用戶將複雜的數據從你的應用複製到其他應用中

        • 你想使用搜索框架提供自定義搜索建議

      2. 創建步驟

        • 設計原始存儲, 文件數據(照片\音頻…)或者結構化數據(數據庫或數組…)

        • 繼承ContentProvider類, 並實現具體方法

        • 定義提供程序的授權字符串\ URI \ 列名稱

        • 添加其他可選的部分

    • 實例操作

      • 創建數據庫, 這裏不詳細介紹了.

      • 繼承ContentProvider類

        public class DemoContentProvider extends ContentProvider {
        
            @Override
            public boolean onCreate() {
                return false;
            }
        
            @Nullable
            @Override
            public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
                return null;
            }
        
            @Nullable
            @Override
            public String getType(@NonNull Uri uri) {
                return null;
            }
        
            @Nullable
            @Override
            public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
                return null;
            }
        
            @Override
            public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
                return 0;
            }
        
            @Override
            public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
                return 0;
            }
        }
      • 設計內容URI

        • 設計授權

          如果Android包名爲com.example., 則爲提供程序提供com.example..provider 授權

        • 設計路徑結構

          合併上一段的權限來生成內容URI : com.example..provider/table1 或者table2

        • 處理內容URI ID

          末尾有_ID值就是來對錶的單個行的訪問.

        • URI模式

          由於有實用類UriMatcher, 所以可以使用以下通配符來匹配內容:

          • ” * ” : 匹配任意長度的任意字符

          • ” # ” : 匹配任意長度的數字

          標準的URI:
          content://com.example.app.provider/….

      • 綜合代碼如下:

        public class DemoContentProvider extends ContentProvider {
            private static final int TABLE1_DIR = 0;
            private static final int TABLE1_ITEM = 1;
        
            private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        
            static {
                sUriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
                sUriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
            }
        
            @Override
            public boolean onCreate() {
                return false;
            }
        
            @Nullable
            @Override
            public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
                SQLiteDatabase db = dbHelper.getReadableDatabase();
                Cursor cursor = null;
                switch (sUriMatcher.match(uri)) {
                    case TABLE1_DIR:
                        //查詢table1表中的所有數據
                        break;
                    case TABLE1_ITEM:
                        //查詢table1表中的單條數據
                        break;
                    default:
                        break;
                }
                return cursor;
            }
        
            @Nullable
            @Override
            public String getType(@NonNull Uri uri) {
                switch (sUriMatcher.match(uri)) {
                    case TABLE1_DIR:
                        return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
                    case TABLE1_ITEM:
                        return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
                    default:
                        break;
                }
                return null;
            }
        
            @Nullable
            @Override
            public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
                return null;
            }
        
            @Override
            public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
                return 0;
            }
        
            @Override
            public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
                return 0;
            }
        }

      不知道大家有沒有看到getType這個方法,返回了一些莫名其妙的字符串

      其實這些都是MIME類型的數據

      格式如下:

      • 必須vnd開頭
      • 路徑結尾的話就後接android.cursor.dir/ , 若是id結尾就接android.cursor.item/
      • 最後接上 vnd. < authority > . < path >
  • 總結

    這個內容提供器有很多demo , 需要結合數據庫來講, 我想等講完數據庫再上傳這個DEMO吧.謝謝大家看我的學習筆記!

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