日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅析调用android的content provider(一)

發布時間:2023/12/20 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅析调用android的content provider(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? 在Android下,查詢聯系人、通話記錄等,需要用到content provider。但是,調用content provider時,Android框架內部是如何做的呢?這一系列文章就是解決這個問題的,所采用的開發環境及源碼都是基于Android 1.6版本。
  • 概述
?? ? ??總的來說此問題分為兩個步驟:?
  • 初始化content provider。這一階段主要是參照AndroidManifest.xml,初始化content provider。注意這里只有當包含content provider的進程運行的時候,才會對該進程內所有的content provider進行初始化。其它provider是按需初始化的(后續文章會介紹該問題)。 ?
  • 調用content provider,進行數據庫操作。這個調用通常發生在用戶定義的Activity子類的相關接口內。調用時,首先會獲取對應的content provider對象(有可能是代理對象)。然后,再調用(直接調用或者通過IBinder接口)。
  • ?? ? ??本文主要探討第一個問題:初始化content provider。
    • 應用進程的管理模型

    ?? ? ??Android框架內,應用程序Java代碼的入口為ActivityThread.main。用來管理不同的應用的服務名稱為activity。它的模型大致為:


    ?? ? ??左邊為多個應用進程,每個進程中有個主線程ActivityThread.main,Looper.loop()是主線程的消息循環。所有的應用進程都是通過IBinder機制和ActivityManagerService進程進行交互的。應用進程為了能調用activity服務進程的ActivityManagerService中的方法,必須通過ActivityManagerProxy類。activity服務進程則通過ApplicationThreadProxy類與服務進程的ApplicationThread通信。ApplicationThread的作用主要是將activity服務進程的調用轉換為ActivityThread主線程中的消息,從而保證ActivityManagerService的調用是異步的。

    ?? ? ??右邊的activity服務進程是所有應用的服務進程,用于管理應用進程。啟動新的應用進程時,會向zygote服務進程發送socket消息。zygote接收到消息后,則會啟動新的delvik虛擬機,然后運行ActivityThread.main,啟動新的應用。

    • PackageManagerService

    ?? ? ??PackageManagerService也是一個服務,是用來管理手機內所有的apk包的。調用它的方式和調用ActivityManagerService是一樣的,通過IBinder。它的初始化入口為PackageManagerService.main:

    [java]?view plaincopy
  • public?static?final?IPackageManager?main(Context?context,?boolean?factoryTest)?{??
  • ????PackageManagerService?m?=?new?PackageManagerService(context,?factoryTest);??
  • ????ServiceManager.addService("package",?m);??
  • ????return?m;??
  • }??

  • ?? ? ??main方法主要是創建一個PackageManagerService,然后注冊到ServiceManager中,名稱為"package”。PackageManagerService的構造函數中,會去查找系統目錄和應用目錄下的apk文件,以獲取應用的包相關的信息;比如:包名稱,包含的Acvity、Provider等。

    [java]?view plaincopy
  • //?……??
  • scanDirLI(mSystemAppDir,?PackageParser.PARSE_IS_SYSTEM,?scanMode);??
  • //?……??
  • scanDirLI(mAppInstallDir,?0,?scanMode);??
  • //?……??

  • ?? ? ??scanDirLI函數中,對于每個package,使用函數scanPackageLI解析其中的信息(此處應該是讀取AndroidManifest.xml)。scanPackageLI檢查相關信息后,又會調用另一個scanPackageLI。這個函數內部會掃描到手機內所有的Provider信息:

    [java]?view plaincopy
  • PackageParser.Provider?p?=?pkg.providers.get(i);??
  • p.info.processName?=?fixProcessName(pkg.applicationInfo.processName,??
  • ????????p.info.processName,?pkg.applicationInfo.uid);??
  • mProvidersByComponent.put(new?ComponentName(p.info.packageName,??
  • ????????p.info.name),?p);??

  • ?? ? ??mProvidersByComponent保存了所有的provider信息,這部分數據源自于manifest。每個數據包含了PackageParser.Provider、包名稱和Provider的類名。

    ?? ? ??到這里,我們可以看到,PackageManagerService真的是用來管理手機的應用包的。通過它可以知道所有的系統可用資源。當然這些資源只是一些靜態信息。通過這些信息,可以創建應用進程、初始化相關的Android組件。

    • 應用進程的初始化
    ?? ? ??先看一下ActivityThread.main的實現,它創建了一個ActivityThread對象,初始化之后,進入消息循環。

    [java]?view plaincopy
  • public?static?final?void?main(String[]?args)?{??
  • ????//?......??
  • ????ActivityThread?thread?=?new?ActivityThread();??
  • ????thread.attach(false);??
  • ??
  • ????Looper.loop();??
  • ??
  • ????//?......??
  • }??

  • ?? ? ??attach函數中,回去調用ActivityManagerService.attachApplication方法。

    [java]?view plaincopy
  • mgr.attachApplication(mAppThread);??

  • ?? ? ??此時,會進入ActivityManagerService的進程空間,進入方法attachApplicationLocked,它會去獲取和當前客戶端應用程序關聯的Provider信息。

    [java]?view plaincopy
  • List?providers?=?generateApplicationProvidersLocked(app);??

  • ?? ? ??根據上面的信息,很容易知道此處是通過PackageManagerService獲取Provider信息的。參數app表明,只是取運行在該app內的Provider。根據Android的文檔,content provider必須在對應的AndroidManifest.xml中定義。默認情況下,是運行在安裝包名稱命名的進程里面。你也可以在android:process屬性中制定所屬的進程名稱。另一個重要的屬性android:multiprocess則可以指定provider的初始化方式,是分散在調用端進程中,從而避免進程間通信;還是只初始化在某個進程內,各個調用端只保留provider的代理。

    ?? ? ??隨后,通過下面的方法調用,返回到應用程序的進程空間,參數中包含了上面獲得的providers。此處的thread實際上就是應用端的ApplicationThread對象。

    [java]?view plaincopy
  • thread.bindApplication(processName,?app.instrumentationInfo?!=?null??
  • ??????????app.instrumentationInfo?:?app.info,?providers,??
  • ????????app.instrumentationClass,?app.instrumentationProfileFile,??
  • ????????app.instrumentationArguments,?app.instrumentationWatcher,?testMode,???
  • ????????isRestrictedBackupMode,?mConfiguration,?getCommonServicesLocked());??

  • ?? ? ??ApplicationThread.bindApplication會發送BIND_APPLICATION消息給主線程。主線程會調用ActivityThread.handleBindApplication方法。這個函數里面主要分兩步:一是根據需要創建Application、ApplicationContext和ApplicationContentResolver對象。因為,有可能多個apk運行在一個進程中,那么它們內部的組件(Component)執行的上下文(context)是不一樣的。這幾個對象實際上就是provider執行的上下文。二是根據傳遞過來的provider信息,創建provider實例,并保存在ActivityThread.mProviderMap中。具體的實例化provider過程如下(下面的代碼位于ActivityThread.handleBindApplication中):

    [java]?view plaincopy
  • List<ProviderInfo>?providers?=?data.providers;??
  • if?(providers?!=?null)?{??
  • ????installContentProviders(app,?providers);??
  • }??

  • ?? ? ??獲取ActivityManagerService傳遞過來的provider信息,并在本進程中初始化。具體的,installContentProviders方法中,會對每個provider調用installProvider方法:

    [java]?view plaincopy
  • IContentProvider?cp?=?installProvider(context,?null,?cpi,?false);??

  • ?? ? ??installProvider方法中,主要是實例化Provider,并保存到mProviderMap中:

    [java]?view plaincopy
  • final?java.lang.ClassLoader?cl?=?c.getClassLoader();??
  • localProvider?=?(ContentProvider)cl.??
  • ????loadClass(info.name).newInstance();??
  • provider?=?localProvider.getIContentProvider();??
  • //?......??
  • //?Cache?the?pointer?for?the?remote?provider.??
  • String?names[]?=?PATTERN_SEMICOLON.split(info.authority);??
  • for?(int?i=0;?i<names.length;?i++)?{??
  • ????ProviderRecord?pr?=?new?ProviderRecord(names[i],?provider,??
  • ????????????localProvider);??
  • ????try?{??
  • ????????provider.asBinder().linkToDeath(pr,?0);??
  • ????????mProviderMap.put(names[i],?pr);??
  • ????}?catch?(RemoteException?e)?{??
  • ????????return?null;??
  • ????}??
  • }??
  • ?? ? ??上面的installContentProviders方法執行完成之后,會調用ActivityManagerService.publishContentProviders方法,將provider注冊到ActivityManagerService中,方便其它應用進程獲取。這里面有兩個參數,一個是ApplicationThread對象,另一個是provider實例信息。

    [java]?view plaincopy
  • try?{??
  • ????ActivityManagerNative.getDefault().publishContentProviders(??
  • ????????getApplicationThread(),?results);??
  • }?catch?(RemoteException?ex)?{??
  • }??

  • ?? ? ??ActivityManagerService.publishContentProviders的實現也很簡單,主要是將provider信息保存到ActivityManagerService.mProvidersByName中。具體參見源碼。
    • 總結
    ?? ? ??本文主要介紹了Android系統內provider的初始化,Android系統默認是會初始化一些provider的,比如:ContactsProvider。它們的初始化和本文介紹的流程應該差不多,主要是在應用進程初始化時獲取provider的信息,然后實例化provider,最后將實例化的provider保存到ActivityManagerService中,供其它應用進程使用。需要說明的一點是,應用進程內可以運行多個apk中的組件。

    ?? ? ??下一篇文章會介紹調用provider的流程。

    分享到:?

    轉載于:https://www.cnblogs.com/zsw-1993/p/4879932.html

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的浅析调用android的content provider(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。