Android - ContentProvider機制

如下資料摘錄整理自老羅的Android之旅博客,是對老羅的博客關於Android底層原理的一個抽象的知識歸納總結(若有錯誤歡迎指出)(侵刪):
http://blog.csdn.net/luoshengyang/article/details/8923485
http://blog.csdn.net/luoshengyang/article/details/12957169數據庫

整理by Doingide

 

        安裝應用程序的時候,並不會把相應的Content Provider加載到內存中來,系統採起的是懶加載的機制,等到第一次要使用這個Content Provider的時候,系統纔會把它加載到內存中來,下次再要使用這個Content Provider的時候,就能夠直接返回
 
Android應用程序組件Content Provider在應用程序之間共享數據的原理
        Content Provider組件在不一樣應用程序之間傳輸數據是基於 匿名共享內存機制來實現的(在應用程序進程之間以匿名共享內存的方式來傳輸數據效率是很是高的,由於它們之間只須要傳遞一個文件描述符就能夠了):
        首先 在第三方應用程序這一側,當它須要訪問Content Provider中的數據時,它會在本進程中 建立一個CursorWindow對象,它在內部建立了一塊匿名共享內存,同時,它實現了Parcel接口,所以它能夠在進程間傳輸。接下來第三方應用程序 把這個CursorWindow對象(連同它內部的匿名共享內存文件描述符)經過Binder進程間調用傳輸到Content Provider這一側。這個匿名共享內存文件描述符傳輸到Binder驅動程序的時候,Binder驅動程序就會在目標進程(即Content Provider所在的進程)中 建立另外一個匿名共享文件描述符,指向前面已經建立好的匿名共享內存,所以,就實現了在 兩個進程中共享同一塊匿名內存
        在 Content Provider這一側利用在Binder驅動程序爲它建立好的這個匿名共享內存文件描述符,在本進程中建立了一個CursorWindow對象。如今,Content Provider開始要從本地中從數據庫中查詢第三方應用程序想要獲取的數據了。Content Provider首先會建立一個 SQLiteCursor對象,即SQLite數據庫遊標對象,它繼承了AbstractWindowedCursor類,後者又繼承了AbstractCursor類,而AbstractCursor類又實現了CrossProcessCursor和Cursor接口。其中,最重要的是在AbstractWindowedCursor類中,有一個成員變量mWindow,它的類型爲CursorWindow,這個成員變量是經過AbstractWindowedCursor的子類SQLiteCursor的setWindow成員函數來設置的。這個SQLiteCursor對象設置好了父類AbstractWindowedCursor類的mWindow成員變量以後,它就具備傳輸數據的能力了,由於這個mWindow對象內部包含一塊匿名共享內存。此外,這個SQLiteCursor對象的內部有兩個成員變量,一個是SQLite數據庫對象mDatabase,另一個是SQLite數據庫查詢對象mQuery。SQLite數據庫查詢對象mQuery的類型爲SQLiteQuery,它繼承了SQLiteProgram類,後者又繼承了SQLiteClosable類。SQLiteProgram類表明一個數據庫存查詢計劃,它的成員變量mCompiledSql包含了一個已經編譯好的SQL查詢語句, SQLiteCursor對象就是利用這個編譯好的SQL查詢語句來得到數據的,可是它並非立刻就去獲取數據的,而是等到須要時纔去獲取
        那麼,要等到何時纔會須要獲取數據呢?通常來講,若是第三方應用程序在請求Content Provider返回數據時,若是指定了要返回關於這些數據的元信息時,例如數據條目的數量,那麼Content Provider在把這個SQLiteCursor對象返回給第三方應用程序以前,就會去獲取數據,由於只有獲取了數據以後,才知道數據條目的數量是多少。SQLiteCursor對象經過調用成員變量mQuery的fillWindow成員函數來把從SQLite數據庫中查詢獲得的數據保存其父類AbstractWindowedCursor的成員變量mWindow中去,即保存到第三方應用程序建立的這塊匿名共享內存中去。若是第三方應用程序在請求Content Provider返回數據時,沒有指定要返回關於這些數據的元信息,那麼,就要等到第三方應用程序首次調用這個從Content Provider處返回的SQLiteCursor對象的數據獲取方法時,纔會真正執行從數據庫存中查詢數據的操做,例如調用了SQLiteCursor對象的getCount或者moveToFirst成員函數時。這是一種數據懶加載機制,須要的時候纔去加載,這樣就提升了數據傳輸過程當中的效率。
        上面說到, Content Provider向第三方應用程序返回的數據其實是一個SQLiteCursor對象,那麼,這個SQLiteCursor對象是如何傳輸到第三方應用程序的呢?由於它自己並非一個Binder對象,咱們須要對它進行適配一下。首先,Content Provider會根據這個SQLiteCursor對象來建立一個CursorToBulkCursorAdaptor適配器對象,這個適配器對象是一個Binder對象,所以,它能夠在進程間傳輸,同時,它實現了IBulkCursor接口。Content Provider接着就經過Binder進程間通訊機制把這個CursorToBulkCursorAdaptor對象返回給第三方應用程序,第三方應用程序獲得了這個CursorToBulkCursorAdaptor以後,再在本地建立一個BulkCursorToCursorAdaptor對象,這個BulkCursorToCursorAdaptor對象的繼承結構和SQLiteCursor對象是同樣的,不過,它沒有設置父類AbstractWindowedCursor的mWindow成員變量,所以,它只能夠經過它內部的CursorToBulkCursorAdaptor對象引用來訪問匿名共享內存中的數據,即經過訪問Content Provider這一側的SQLiteCursor對象來訪問共享數據。
 
 
Content Provider的共享數據更新通知機制
        ContentObserver類的成員變量mTransport是一個Binder對象,它是要傳遞給ContentService服務的,以便當ContentObserver所監控的數據發生變化時,ContentService服務能夠經過這個Binder對象通知相應的ContentObserver它監控的數據發生變化了
         Android應用程序組件Content Provider中的數據更新通知機制和Android系統中的廣播(Broadcast)通知機制的實現思路是類似的。然而,Content Provider中的數據監控機制與Android系統中的廣播機制又有三個主要的區別:
  1. 一是前者是經過URI來把通知的發送者和接收者關聯在一塊兒的,然後者是經過Intent來關聯的
  2. 二是前者的通知註冊中心是由ContentService服務來扮演的,然後者是由ActivityManagerService服務來扮演的
  3. 三是前者負責接收數據更新通知的類必需要繼承ContentObserver類,然後者要繼承BroadcastReceiver類。
        之因此會有這些區別,是因爲Content Proivder組件的數據共享功能自己就是創建在URI的基礎之上的,所以專門針對URI來設計另一套通知機制會更實用和方便,而Android系統的廣播機制是一種更加通用的事件通知機制,它的適用範圍會更普遍一些。
相關文章
相關標籤/搜索