天天看點

寫給Android App開發人員看的Android底層知識(7)

這個系列一共8篇文章,這裡是第7篇,我們講ContentProvider。

(十二)ContentProvider

(1)ContentProvider是什麼?

ContentProvider,簡稱CP。

做App開發的同學,尤其是電商類App,對CP并不熟悉,對這個概念的最大程度的了解,也僅僅是建立在書本上,它是Android四大元件中的一個。

做系統管理類的App,比如說手機助手這種,有機會頻繁使用CP。

而對于應用類App,資料通常存在伺服器端,其它應用類App也想使用的時候,一般都是從伺服器取資料,是以沒機會使用到CP。

有時候我們會在自己的App中讀取通信錄或者短信的資料,這時候就需要用到CP了。通信錄或者短信的資料,是以CP的形式提供的,我們在App這邊,是使用方。

      對于做應用類App的同學,很少有機會自定義CP供其它App使用。

我們快速回顧一下在App中怎麼使用CP。

寫給Android App開發人員看的Android底層知識(7)

1)定義CP的App1:

       在App1中定義一個CP的子類MyContentProvider,并在Manifest中聲明,為此要在MyContentProvider中實作CP的增删改查四個方法:

寫給Android App開發人員看的Android底層知識(7)
寫給Android App開發人員看的Android底層知識(7)

2)使用CP的App2:

     在App2通路App1中定義的CP,為此,要使用到ContentResolver,它也提供了增删改查4個方法,用于通路App1中定義的CP:

寫給Android App開發人員看的Android底層知識(7)

首先我們看一下ContentResolver的增删改查這4個方法的底層實作,其實都是和AMS通信,最終調用App1的CP的增删改查4個方法,後面我們會講到這個流程是怎麼樣的。

      其次,URI是CP的身份證,唯一辨別。

      我們在App1中為CP聲明URI,也就是authorities的值為baobao,那麼在App2中想使用它,就在ContentResolver的增删改查4個方法中指定URI,格式為:

uri = Uri.parse("content://baobao/");

      接下來把兩個App都進入debug模式,就可以從App2調試進入App1了,比如說,query操作。

     (2)CP的本質

      CP的本質是把資料存儲在SQLite資料庫中。

      各種資料源,有各種格式,比如短信、通信錄,它們在SQLite中就是不同的資料表,但是對外界的使用者而言,就需要封裝成統一的通路方式,比如說對于資料集合而言,必須要提供增删改查四個方法,于是我們在SQLite之上封裝了一層,也就是CP。

     (3)匿名共享記憶體(ASM)

CP讀取資料使用到了匿名共享記憶體,英文簡稱ASM,是以你看上面CP和AMS通信忙的不亦樂乎,其實下面别有一番風景。

      關于ASM的概念,它其實也是個Binder通信,我畫個圖哦,你們就明白了:

寫給Android App開發人員看的Android底層知識(7)

什麼?還沒看懂?那我再畫一個類的互動關系圖:

寫給Android App開發人員看的Android底層知識(7)

這裡的CursorWindow就是匿名共享記憶體。

這個流程,簡單來說是這樣的:

1)Client内部有一個CursorWindow對象,發送請求的時候,把這個CursorWindow類型的對象傳過去,這個對象暫時為空。

2)Server收到請求,搜集資料,填充到這個CursorWindow對象。

      3)Client讀取内部的這個CursorWindow對象,擷取到資料。

      由此可見,這個CursorWindow對象,就是匿名共享記憶體,這是同一塊匿名記憶體。   

舉個生活中的例子就是,你定牛奶,在你家門口放個箱子,送牛奶的人每天早上往這個箱子放一袋牛奶,你睡醒了去箱子裡取牛奶。這個牛奶箱就是匿名共享記憶體。

     (4)CP與AMS的通信流程

      接下來我們看一下CP是怎麼和AMS通信的。

能堅持看到這裡的人,都不容易。我努力多貼圖,不貼代碼,即使有代碼,也是App開發人員能看懂的代碼。

還是拿App2想通路App1中定義的CP為例子。我們就看CP的insert方法。

寫給Android App開發人員看的Android底層知識(7)

     上面這5行代碼,包括了啟動CP和執行CP方法兩部分,分水嶺在insert方法,insert方法的實作,前半部分仍然是在啟動CP,當CP啟動後擷取到CP的代理對象,後半部分是通過代理對象,調用insert方法。

整體的流程如下圖所示:

寫給Android App開發人員看的Android底層知識(7)

1)App2發送消息給AMS,想要通路App1中的CP。

2)AMS檢查發現,App1中的CP沒啟動過,為此新開一個程序,啟動App1,然後擷取到App1啟動的CP,把CP的代理對象傳回給App2。

      3)App2拿到CP的代理對象,也就是IContentProvider,就調用它的增删改查4個方法了,接下來就是使用ASM來傳輸資料或者修改資料了,也就是上面提到的CursorWindow這個類,取得資料或者操作結果即可,作為App的開發人員,不需要知道太多底層的詳細資訊,用不上。

至此,關于CP的介紹就結束了。下一篇文章,我們看一下App的安裝流程,也就PMS。