Android 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 <wbr>ContentProvider詳解
   attribute的定義可以參考http://developer.android.com/guide/topics/manifest/manifest-intro.html

  下面重點探討Content Provider的實現和使用。

 

二.什麼是ContentProvider

Content Provider維護特定的應用數據,並可以讓其它應用輕鬆訪問該數據。對數據使

用者來說它是數據提供者。它提供統一的接口對數據進行操作,使用者不用關心數據到底是如何存儲的以及數據類型到底是什麼。也就是說,ContentProvider作爲數據提供者,提供了對外共享本地數據一種機制,使Android應用能方便地基於該機制進行數據訪問。

   爲了便於管理和訪問,每個ContentProvider必須有唯一標示,用Uri表示。Uri類似http url, 構成如下:

    content://authority/path

   所有Content ProviderUri必須以content://開頭,這是Android規定的。

   authority是個字符串,它由開發者自己定義,用於來唯一標示一個ContentProvider。系統會根據這個標示查找ContentProvider

    path也是字符串,表示要操作的數據。可根據自己的實現邏輯來指定:
content://contacts/people表示要操作ContentProvidercontacts下的people

content://com.android.contacts/people/#表示要操作表people中特定id的行(記錄)

content://downloads/download/10/name表示要操作id10的行的name字段。

content://downloads/download/*表示操作download表中的所有字段。

總之,#匹配一個數字字符串,*匹配一個文本字符串。

 

三.ContentProvider 的實現和使用    

Android <wbr>ContentProvider詳解

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

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

Android <wbr>ContentProvider詳解

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

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

 

Android <wbr>ContentProvider詳解


 

四.ContentProvider內部機制

 

1ContentProvider接口調用過程

    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來進行相關處理/檢查。如果該ProviderSingle ProcessActivityManagerService會爲ContentProvider創建一個獨立Process;如果是MultiProcess,說明每個調用者可以擁有獨立的ContentProvider實例,於是ActivityManagerService只是返回ContentProvider的相關信息給ActivityThread,由ActivityThread負責ContentProvider的實例化,此時ContentProvider運行在調用者Process中。實例化後,IConentProvider會返回給調用者,通過該接口可以調用所需功能。

    ActivityThread本地維護一個mProviderMap<ProviderName, ProviderRecord>,記錄已被引用的ContentProvider, 同時使用引用計數mProviderRefCountMap<IBinder,ProviderRefCount>記錄特定ContentProvider的引用情況。

Android <wbr>ContentProvider詳解

 

2ContentProvider實例創建過程

    ContentProvider實例的創建與multiprocess屬性有關係(Androidmanifest.xml裏指定),個人認爲理解成多進程並不準確。應該理解爲ContentProvider的多實例,不會存在多個ContentProvider進程的情況,ContentProvider可能存在多個實例。

1)對於android:multiprocess=trueContentProvider,意味着可以多實例,那麼由調用者在自己的進程空間實例化一個ContentProvider對象,此時定義ContentProvider的App可能並沒有啓動

Android <wbr>ContentProvider詳解

 

注意:ContentProvider是否多實例,還得看contentProvideruid與調用者的uid是否相同或contentProvideruidSystem user。具體邏輯是:

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啓動流程。

 

3ContentProvider的加載/發佈過程

   ContentProvider不能單獨發佈,總是被打包到某個Android應用(apk)裏。APK被安裝之後,實例化之後每個Android應用都有一個Application實例,每個ActivityService有一個ApplicationContext實例。

   Android應用程序的入口函數是ActivityThread.main(),該函數不僅創建了ActivityThread實例以及消息循環機構,而且創建了ApplicationThread實例,通過此實例向ActivityManager Service(AMS)提供IApplicationThread接口,AMS正是通過該接口調度和管理Activity。  

   ActivityThread通過attachApplication()把自己的ApplicationThread實例告知AMS

AMS根據thread信息更新進程記錄(ProcessRecord)並調用threadbindApplication()進行初始化工作並創建ApplicationContextApplication實例,然後安裝package裏聲明的所有contentProvider 主要過程如下:

Android <wbr>ContentProvider詳解

AMS維護了很多信息,其中比較重要的有:

mProcessNames     包名(processName)和進程信息(ProcessRecord)映射表

mProvidersByName:  Provider發佈名和Provider信息(ContentProviderRecord)映射表

mProvidersByClass  Provider類名和Provider信息(ContentProviderRecord)映射表

conProviders屬於ProcessRecord信息,特定Process正在使用的ContentProvider及其個數映射表       

pubProviders屬於ProcessRecord信息,特定Process已經PublishedProvider名和Provider信息

             (ContentProviderRecord)映射表

ActivityThread維護了3個與ContentProvider相關的Map

mProviderMap        記錄本應用已使用的Provider信息:<Provider發佈名, ProviderRecord>

mProviderRefCountMap: 記錄本應用已使用的Provider引用計數信息:<IBinder,ProviderRefCount>

mLocalProviders     記錄本地加載的Provider信息:<IBinder,ProviderRecord>

 

4ContentProvider通知機制

Android <wbr>ContentProvider詳解
 

注意:這個通知機制需要ContentProvider的實現者在實現insert/delete/query/update接口時調用ContentResolvernotifyChange(),否則沒法實現數據變化的通知。

  

參考代碼:

\frameworks\base\core\java\android\app\ActivityThread.java

\frameworks\base\core\java\android\content\ContentResolver.java

\frameworks\base\core\java\android\content\ContentContent.java

\frameworks\base\core\java\android\content\ContentService.java

\frameworks\base\core\java\android\database\ContentObserver.java

\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

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