ContentProvider的詳解

轉載自:http://blog.sina.com.cn/s/blog_49f62c350101hhhl.html

一.Android四大組件

Android四大組件是Activity, Service, Content Provider, Broadcast Receiver。

Activity作爲程序界面,直接與用戶交互

Service運行在後臺,沒有界面,完成特定的功能

ContentProvider維護應用數據,方便應用本身或其它應用訪問

Broadcast Receiver提供異步廣播消息接收機制,便於各應用/組件進行交互

通過AndroidManifest.xml, 可以看到一個應用使用了哪些組件:

Android ContentProvider詳解
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 的實現和使用

Android ContentProvider詳解

​ 可以看出 , 實現一個自定義的Content Provider,要基於系統提供的基類ContentProvider,需要實現6個接口。大部分接口就是類似數據庫的數據操作接口,實際上Content Provider是需要創建數據庫並對數據庫進行操作的。完成實現之後,在Androidmanifest.xml中聲明自己的Content Provider以及與Provider相關的permission聲明(可以沒有permission定義)。例如:

Android ContentProvider詳解
​ 最後整個應用被編譯成apk。安裝之後,該應用裏的contentProvider就可以被其它應用訪問了。對於Provider使用者來說, 如果特定Provider有permission要求,則要在自己的Androidmanifest.xml中添加指定Permission引用, 如:

Android ContentProvider詳解

​ 使用非常簡單,Android提供了Context級別的ContentResolver對象來對Content Provider進行操作。正是因爲有了ContentResolver, 使用者纔不用關心Provider到底是哪個應用或哪個類實現的。只要知道它的uri就能訪問。ContentResolver對象存在於每個Context中。幾乎所有對象都有自己的Context。

Android ContentProvider詳解
​ 有些情況下,Content Provider使用者想監聽數據的變化,可以註冊一個Observer:

Android <wbr>ContentProvider詳解

四. 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

Android <wbr>ContentProvider詳解

其中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。 主要過程如下:

Android 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信息:

發佈了173 篇原創文章 · 獲贊 41 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章