轉載自:http://blog.sina.com.cn/s/blog_49f62c350101hhhl.html
一.Android四大組件
Android四大組件是Activity, Service, Content Provider, Broadcast Receiver。
Activity作爲程序界面,直接與用戶交互
Service運行在後臺,沒有界面,完成特定的功能
ContentProvider維護應用數據,方便應用本身或其它應用訪問
Broadcast Receiver提供異步廣播消息接收機制,便於各應用/組件進行交互
通過AndroidManifest.xml, 可以看到一個應用使用了哪些組件:
attribute的定義可以參考http://developer.android.com/guide/topics/manifest/manifest-intro.html
下面重點探討Content Provider的實現和使用。
二. 什麼是ContentProvider
Content Provider維護特定的應用數據,並可以讓其它應用輕鬆訪問該數據。對數據使
用者來說它是數據提供者。它提供統一的接口對數據進行操作,使用者不用關心數據到底是如何存儲的以及數據類型到底是什麼。也就是說,Content Provider作爲數據提供者,提供了對外共享本地數據一種機制,使Android應用能方便地基於該機制進行數據訪問。
爲了便於管理和訪問,每個Content Provider必須有唯一標示,用Uri表示。Uri類似http url, 構成如下:
content://authority/path
所有Content Provider的Uri必須以content://開頭,這是Android規定的。
authority是個字符串,它由開發者自己定義,用於來唯一標示一個ContentProvider。系統會根據這個標示查找ContentProvider。
path也是字符串,表示要操作的數據。可根據自己的實現邏輯來指定:
content://contacts/people表示要操作ContentProvider爲contacts下的people表
content://com.android.contacts/people/#表示要操作表people中特定id的行(記錄)。
content://downloads/download/10/name表示要操作id爲10的行的name字段。
content://downloads/download/*表示操作download表中的所有字段。
總之,#匹配一個數字字符串,*匹配一個文本字符串。
**三.**ContentProvider 的實現和使用
可以看出 , 實現一個自定義的Content Provider,要基於系統提供的基類ContentProvider,需要實現6個接口。大部分接口就是類似數據庫的數據操作接口,實際上Content Provider是需要創建數據庫並對數據庫進行操作的。完成實現之後,在Androidmanifest.xml中聲明自己的Content Provider以及與Provider相關的permission聲明(可以沒有permission定義)。例如:
最後整個應用被編譯成apk。安裝之後,該應用裏的contentProvider就可以被其它應用訪問了。對於Provider使用者來說, 如果特定Provider有permission要求,則要在自己的Androidmanifest.xml中添加指定Permission引用, 如:
使用非常簡單,Android提供了Context級別的ContentResolver對象來對Content Provider進行操作。正是因爲有了ContentResolver, 使用者纔不用關心Provider到底是哪個應用或哪個類實現的。只要知道它的uri就能訪問。ContentResolver對象存在於每個Context中。幾乎所有對象都有自己的Context。
有些情況下,Content Provider使用者想監聽數據的變化,可以註冊一個Observer:
四. ContentProvider內部機制
1.ContentProvider接口調用過程
ContentProvider依賴ContentResolver/ActivityThread/ActivityManagerService對外提供
服務。雖然ContentProvider的用法以及表現形式不是一個Service,實際上它可以看作是ActivityManagerService提供的一種服務, 它實現了IBinder接口。
首先調用者通過特定uri調用特定ContentProvider的接口函數,比如insert(), 此時ContentResolver會通過uri獲取特定ContentProvider的實例,ActivityThread檢查本地Cache,如果發現此ContentProvider已經被引用過,則直接直接取出ContentProvider返回給調用者。如果沒有發現,由於 ContentProvider可能已經被load了,可能還沒有load;可能要創建Process,可能要檢查permission,所以ActivityThread調用到ActivityManagerService來進行相關處理/檢查。如果該Provider是Single Process,ActivityManagerService會爲ContentProvider創建一個獨立Process;如果是MultiProcess,說明每個調用者可以擁有獨立的ContentProvider實例,於是ActivityManagerService只是返回ContentProvider的相關信息給ActivityThread,由ActivityThread負責ContentProvider的實例化,此時ContentProvider運行在調用者Process中。實例化後,IConentProvider會返回給調用者,通過該接口可以調用所需功能。
ActivityThread本地維護一個mProviderMap
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& (uid == Process.SYSTEM_UID || uid == app.info.uid);
}
2)對於android:multiprocess=false(默認值)的ContentProvider,由系統把定義該ContentProvider的App啓動起來(一個獨立的Process)並實例化ContentProvider,這種ContentProvider只有一個實例,運行在自己App的Process中。所有調用者共享該ContentProvider實例,調用者與ContentProvider實例位於兩個不同的Process
其中Process.start()->zygoteSendArgsAndGetPid()->ZygoteInit.runSelectLoopMode()
-> ZygoteConnection.runOnce() -> Zygote.forkAndSpecialize()->RuntimeInit.zygoteInit()
-> invokeStaticMain()->MethodAndArgsCaller.run()->Method.invokeNative
->ActivityThread.main(),這是通用的APK啓動流程。
3)ContentProvider的加載/發佈過程
ContentProvider不能單獨發佈,總是被打包到某個Android應用(apk)裏。APK被安裝之後,實例化之後每個Android應用都有一個Application實例,每個Activity或Service有一個ApplicationContext實例。
Android應用程序的入口函數是ActivityThread.main(), 該函數不僅創建了ActivityThread實例以及消息循環機構,而且創建了ApplicationThread實例,通過此實例向Activity Manager Service(AMS)提供IApplicationThread接口,AMS正是通過該接口調度和管理Activity。
ActivityThread通過attachApplication()把自己的ApplicationThread實例告知AMS。
AMS根據thread信息更新進程記錄(ProcessRecord)並調用thread的bindApplication()進行初始化工作並創建ApplicationContext和Application實例,然後安裝package裏聲明的所有contentProvider。 主要過程如下:
AMS維護了很多信息,其中比較重要的有:
mProcessNames: 包名(processName)和進程信息(ProcessRecord)映射表
mProvidersByName: Provider發佈名和Provider信息(ContentProviderRecord)映射表
mProvidersByClass: Provider類名和Provider信息(ContentProviderRecord)映射表
conProviders:屬於ProcessRecord信息,特定Process正在使用的ContentProvider及其個數映射表
pubProviders:屬於ProcessRecord信息,特定Process已經Published的Provider類名和Provider信息
(ContentProviderRecord)映射表
ActivityThread維護了3個與ContentProvider相關的Map:
mProviderMap: 記錄本應用已使用的Provider信息: