天天看點

自定義ContentProvider

ContentProvider作為安卓的四大元件之一,在看開發中用到的頻率遠不如其他三個,以至于我都把這個東西給忘了,最近由于工作原因,不得不重新拾起來總結一下,那麼今天就來說說自定義ContentProvider吧。

今天的案例是這樣的,我們有兩個App,一個叫做cpHost,作為内容提供者;另外一個叫做cpTest,專門用來操作這個cpHost中的資料。我們的cpHost中有一個資料庫,該資料庫中有一個User表,我們通過内容提供者将這個User表共享出去,供其他App調用。下面我們就來看看怎麼實作這樣一個效果。

既然用到資料庫存儲使用者表,那麼毫無疑問我們需要一個DBHelper,如下:

我們建立一個使用者表,然後在在MainActivity中将該表中的資料顯示出來,這樣友善我們後面看到操作效果,于是我們需要一個listview,看看MainActivity的布局檔案:

MainActivity.java:

這裡之是以把給ListView設定Adapter的方法放在onResume()方法中執行,主要是為了測試友善,沒有其他意思,那麼我們在來看看UserBean:

還有一個MyAdapter:

這些都很簡單的顯示部分的代碼,我就不再詳細解釋。說完這些我們終于可以介紹今天的核心内容了,那就是ContentProvider。我們自定義的ContentProvider首先要繼承ContentProvider,繼承ContentProvider之後,我們會看到有多個方法需要我們實作,分别onCreate()、query、getType、insert、delete、update,主要是這幾個方法,通過方法名字我們都能看出這幾個方法的含義,就是執行增删改查操作,其中onCreate在應用啟動的時候會調用,我們可以在裡邊做一些初始化的操作,但是不宜做一些耗時過長的操作,否則會導緻應用啟動時間變長,造成不好的使用者體驗。在其他的方法中我們分别執行相應的增删改查操作即可。說到這裡,我們不得不介紹ContentProvider中另外一個非常重要的東西,那就是Uri。

Uri是ContentResolver執行CRUD方法時的重要參數,我們可以從Uri中提取出我們要操作的資料對象,要操作哪一條資料等等資訊,UriMatcher對象映射Uri的傳回碼,我們可以使用UriMatcher來友善的知道ContentResolver想要幹什麼。下面我們舉例來說明一下:

一般情況下,我們見到的Uri就是這樣的,我們可以将Uri分為三部分,第一部分是固定内容,第二部分是authorities,也就是我們在清單檔案中注冊ContentProvider時的authorities參數,最後一部分表示資料源路徑,可有可無,這些根據自己的項目需求随意定義即可,但是這裡有一些約定俗成的規則,比如:

1.user多數情況下表示我們要操作的表名,因為一個ContentProvider可能涉及到多個表,通過這裡來進行區分。

2.如果user之後沒有參數,預設傳回目前表中所有資料,或者是操作目前表中所有資料

3.user之後的3表示操作資料庫的條件,可以是id,也可以是其他字段。

那麼這麼長一個字元串我們要怎麼提取我們需要的資料呢?難道要用正則?其實不必,這裡就用到我們前面說的UriMatcher,使用UriMatcher會自動對我們的Uri進行比對,但是,在比對之前我們要先定義一下比對規則,如下:

我們一般習慣于在靜态子產品中初始化UriMatcher,我們可以向其中添加比對規則,比如第6行,我們添加了比對規則,如果如果Uri第三部分隻用一個user,那麼比對結果為1,第7行,#表示任意數字,這句話表示如果Uri的第三部分是數字,那麼比對結果為2,第8行,*表示任意字元,user後還跟了第三個參數,那麼比對結果為3,我們以delete方法為例:

調用Uri中的matcher方法來進行比對,系統會根據我們在靜态子產品中的定義來傳回相應的比對結果,根據不同的結果,執行不同的操作,那麼我們有什麼方法可以快速提取出Uri中的參數呢?

這裡我們介紹兩個方法,

1.比如我們的Uri是這樣的:

那麼我們通過uri.getPathSegments()方法可以拿到一個List集合,該集合中放了兩個字元串,第一個是user,第二個是zhangsan

2.比如我們的Uri是這樣的:

那麼我們可以通過ContentUris.parseId(uri)方法獲得10這個數字

以上兩種方式基本已經可以解決我們遇到的所有問題了。說了這麼多,現在給大家看看一個完整的我的自定義ContentProvider:

由于時間關系,有幾個方法沒有實作,不過原理都是一樣的,不多說。

所有這些都做完之後,别忘了在清單檔案中注冊ContentProvider,如下:

這裡解釋一下第三個參數,設定為true表示允許其他App調用,設定為false表示不允許其他App調用。

這裡說完,我們再看看怎麼在cpTest這個App中操作這些資料:

核心代碼如下:

好了,關于自定義ContentProvider就說這麼多。