天天看點

跨程式共享資料——Content Provider 之 建立自己的内容提供器

本子產品共有四篇文章,參考郭神的《第一行代碼》,對Content Provider的學習做一個詳細的筆記,大家可以一起交流一下:

在上一節中,我們學習了如何在自己的程式中通路其他應用程式的資料。總體來說思路還是非常簡單的,隻需要擷取到該應用程式的内容URI,然後借助ContentResolver進行CRUD操作就可以了。可是你有沒有想過,那些提供外部通路接口的應用程式都是如何實作這種功能的呢?它們又是怎樣保證資料的安全性,使得隐私資料不會洩漏出去?學習完本節的知識後,你的疑惑将會被 一 一解開。
建立内容提供器的步驟
1 建立一個類去繼承ContentProvider;
2 在這個類中重寫6個抽象方法(詳見下文)
3 定義自定義代碼常量;
  建立靜态代碼塊,在代碼塊中執行個體化UriMatcher的一個執行個體并調用addURI()将Uri以及對應的自定義代碼常量傳遞進去;
  補充query(),處理比對結果;insert()、update()、delete()同理;
4 補充getType()方法,完畢.
           
下面進行步驟的詳細解析

前面已經提到過,如果想要實作跨程式共享資料的功能,官方推薦的方式就是使用内容提供器,可以通過建立一個類去繼承ContentProvider的方式來建立一個自己的内容提供器。ContentProvider類中有6個抽象方法,我們在使用子類繼承它的時候,需要将這6個方法全部重寫。建立MyProvider繼承自ContentProvider,代碼如下所示(這裡先不用急着寫,到後面待會兒的實戰講解中會告訴大家内容提供器的快捷建立方法):

public class MyProvider 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;
    }
}
           

6大重寫抽象方法解析(其實CRUD操作的跟前一節的差不多):

1.onCreate()
  • 初始化内容提供器的時候調用。
  • 通常會在這裡完成對資料庫的建立和更新等操作。
  • 傳回 true 表示内容提供器初始化成功,傳回 false 則表示失敗。
  • 注意,隻有當存在ContentResoIver嘗試通路我們程式中的資料時,内容提供器才會被初始化。
2.query()
  • 從内容提供器中查詢資料。
  • 使用uri參數來确定查詢哪張表,

    projection參數用于确定查詢哪些列,

    selection和selectionArgs參數用于限制查詢哪些行,

    sortorder參數用于對結果進行排序,

    查洵的結果存放在Cursor對象中傳回。

3.insert()

向内容提供器中添加一條資料。使用uri參數來确定要添加到的表,待添加的資料儲存在

values參數中。添加完成後,傳回一個用于表示這條新記錄的URI。

4,update()

更新内容提供器中已有的資料。使用uri參數來确定更新哪一張表中的資料,新資料儲存在

values參數中,selection和selectionArgs參數用于限制更新哪些行,受影響的行數将作

為傳回值傳回。

5.delete()

從内容提供器中删除資料。使用uri參數來确定删除哪一張表中的資料,selection和

selectionArgs參數用于限制删除哪些行,被删除的行數将作為傳回值傳回。

6、getType()
  • 根據傳入的内容URI來傳回相應的MIME類型。

可以看到,幾乎每一個方法都會帶有Uri這個參數,這個參數也正是調用ContentResoIver的增删改查方法時傳遞過來的。

而現在,我們需要對傳入的Uri參數進行解析,從中分析出調用方期望通路的表和資料。

Uri的兩種寫法
跨程式共享資料——Content Provider 之 建立自己的内容提供器
使用通配符比對Uri
跨程式共享資料——Content Provider 之 建立自己的内容提供器
UriMatcher比對
  • 接着,我們再借助UriMatcher這個類就可以輕松地實作比對内容URI的功能。
  • UriMatcher中提供了一個addURI()方法,這個方法接收3個參數,可以分别把authority、path和一個自定義代碼傳進去。
  • 這樣,當調用UriMatcher的match()方法時,就可以将一個Uri對象傳入,傳回值是某個能夠比對這個Uri對象所對應的自定義代碼,
  • 利用這個代碼,我們就可以判斷出調用方期望通路的是哪張表中的資料了。

修改MyProvider中的代碼,如下所示:

跨程式共享資料——Content Provider 之 建立自己的内容提供器
跨程式共享資料——Content Provider 之 建立自己的内容提供器

上面的代碼簡析:

  • 可以看到,MyProvider中新增了4個整型常量,其中

    TABLEI_DIR表示通路tablel表中的所有資料,

    TABLEI_ITEM表示通路tablel表中的單條資料,

    TABLE2_DIR表示通路table2表中的所有資料,

    TABLE2_ITEM表示通路table2表中的單條資料。

  • 接着在靜态代碼塊裡我們建立了UriMatcher的執行個體,并調用 addURI() 方法,将期望比對的内容URI格式傳遞進去,注意這裡傳入的路徑參數是可以使用通配符的。
  • 然後當 query()方法 被調用的時候,就會通過UriMatcher的match()方法對傳入的Uri對象進行比對,如果發現UriMatcher中某個内容URI格式成功比對了該Uri對象,則會傳回相應的自定義代碼,然後我們就可以判斷出調用方期望通路的到底是什麼資料了。
getType()與MIME類型的感情糾葛

上述代碼隻是以query()方法為例做了個示範,其實insert()、update()、delete()這幾個方法的實作也是差不多的,它們都會攜帶Uri這個參數,然後同樣利用UriMatcher的match()方法判斷出調用方期望通路的是哪張表,再對該表中的資料進行相應的操作就可以了。

除此之外,還有一個方法你會比較陌生,即getType()方法。它是所有的内容提供器都必須提供的一個方法,用于擷取Uri對象所對應的MIME類型。一個内容URI所對應的MIME字元串主要由3部分組成,Android對這3個部分做了如下格式規定。

1.必須以vnd開頭。

2.如果内容URI以路徑結尾,則後接android.cursor.dir/,如果内容URI以id結尾,

則後接android.cursor.item/。

3.最後接上vnd.<authority>.<path>。

跨程式共享資料——Content Provider 之 建立自己的内容提供器
跨程式共享資料——Content Provider 之 建立自己的内容提供器
跨程式共享資料——Content Provider 之 建立自己的内容提供器
接下來,補充getType()
跨程式共享資料——Content Provider 之 建立自己的内容提供器
内容提供器保證隐私資料不會洩漏出去

到這裡,一個完整的内容提供器就建立完成了,現在任何一個應用程式都可以使用ContentResolver來通路我們程式中的資料;

那麼前面所提到的,如何才能保證隐私資料不會洩漏出去呢?其實多虧了内容提供器的良好機制,這個問題在不知不覺中已經被解決了。因為所有的CRUD操作都一定要比對到相應的内容URI格式才能進行的,而我們當然不可能向UnMatcher中添加隐私資料的URI,是以這部分資料根本無法被外部程式通路到,安全問題也就不存在了。