Android資源篇2:從Activity啟動看AssetManager創(chuàng)建

導語 Android系統(tǒng)內部是在什么時候創(chuàng)建AssetManager先较,又是如何創(chuàng)建的携冤? AssetManager與Resource什么關系? Android插件化為什么可以通過重寫addAssetPath方法訪問插件資源闲勺? 本文參考老羅的文章曾棕,并生成自己的見解,若有錯誤之處霉翔,懇請指正睁蕾。 詳見:http://blog.csdn.net/luoshengyang/article/details/8791064

1、AssetManager與Resources

Android中的資源可以分為兩類:

  • 第一類資源,不對應文件的子眶,如string資源瀑凝;

  • 第二類資源,對應文件的臭杰,如layout資源粤咪。

  • 第一類資源只需通過資源ID查找到資源名稱即可,第二類資源需根據資源名稱打開相應文件渴杆。 通過下面這副圖片簡單的分析下資源查找的過程:


    ![2.png](https://upload-images.jianshu.io/upload_images/1986354-c116631c1d715cdd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

如上圖所示寥枝,Resources根據資源ID查找資源,AssetManager根據資源名稱查找資源磁奖。若Resources查找資源時的資源ID對應的資源是文件囊拜,那先根據資源ID查找到資源文件名稱(在resources.arsc中查找到),再通過AssetManager打開相應文件比搭。 看下Resources與AssetManager的成員變量:

  • ContextImpl提供接口getResources可以獲得指向當前APK資源的Resources對象冠跷。

  • Resouces類中的mAssets是AssetManager對象,用來訪問程序的非編譯文件(第二類資源)身诺;mSystem是Resources對象蜜托,用來訪問系統(tǒng)資源包,系統(tǒng)資源包存在/system/framework/framework-res.apk霉赡。

  • AssetManager(Java)中的sSystem是AssetManager對象橄务,用來打開系統(tǒng)資源包文件;mObject是一個int地址穴亏,保存了對應C++層的AssetManager對象地址蜂挪。

  • AssetManager(C++)中的mAssetPaths是資源目錄,mResources為資源表迫肖,mConfig保存了設備的本地配置信息锅劝。

2攒驰、Activity啟動

調用startActivity啟動指定Activity蟆湖,最后會調用ApplicationThread的scheduleLaunchActivity方法。流程如下所示:

  1. scheduleLaunchActivity方法通過H發(fā)送消息H.LAUNCH_ACTIVITY

  2. H的消息處理中玻粪,調用ActivityThread的getPackageInfoNoCheck創(chuàng)建LoadedAPK對象隅津,調用handleLaunchActivity啟動Activity。

  3. 創(chuàng)建的LoadedAPK對象指定資源路徑為當前APK劲室。

  4. handleLaunchActivity啟動Activity伦仍,先調用makeApplication創(chuàng)建Application對象,并未Application關聯(lián)ContextImpl(baseContext)很洋。

  5. 再為啟動的Activity關聯(lián)ComtextImpl(baseContext)充蓝。 該過程如下圖所示,其中AMS(ActivityManagerService)負責Activity聲明周期和Activity堆棧的管理,而ApplicationThread是App進程與AMS通信的Binder谓苟。ApplicationThread通過H(是一個Handler)實現(xiàn)與主線程ActivityThread的通信官脓,進而管理者Activity的聲明周期。

3.png

在上過程中涝焙,首先會為創(chuàng)建的Application關聯(lián)AppContext卑笨,即為Application關聯(lián)ContextImpl;再為啟動的Activity關聯(lián)BaseContext仑撞,同樣為ContextImpl赤兴。該過程都會調用ContextImpl的構造方法,實現(xiàn)ContextImpl的創(chuàng)建隧哮,并調用init方法實現(xiàn)Resources桶良、AssetManager的創(chuàng)建,那接著看ContextImpl的init過程沮翔。

(插一句艺普,Application繼承ContextWrapper,ContextWrapper繼承Context鉴竭;Activity繼承ContextThemeWrapper歧譬,ContextThemeWrapper繼承ContextWrapper。Application與Activity的基類Context是抽象類搏存,其具有成員變量mBaseContext瑰步,采用代理模式,真正的操作都有mBaseContext實現(xiàn)璧眠。而真正實現(xiàn)Context方法的類只有ContextImpl缩焦,因此在創(chuàng)建Activity或Application都需要為其關聯(lián)一個ContextImpl對象)

3、ActivityManager創(chuàng)建

接著上一步的ContextImpl的創(chuàng)建责静,先看下時序圖:

4.png

該過程的主要實現(xiàn)了:


![6.png](https://upload-images.jianshu.io/upload_images/1986354-13db298d833ef0d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

過程還是比較多的袁滥,挑幾步好好看下。

3.1灾螃、第1步:init

該步中調用LoadeAPk的getResources(..)方法獲得Resources對象题翻,LoadedAPK在上面Activity啟動流程中進行創(chuàng)建(LoadedAPK保存了當前APK信息)。

6.png

3.2腰鬼、第3步:getTopLevelResources

在第2步調用LoadedAPK的getResources方法中嵌赠,它會調用ActivityThread的getTopLevelResources方法。該方法的主要內容有:


7.png

如上所示熄赡,該方法主要完成以下功能:

  1. 從Map緩存中取Resources對象姜挺,有直接返回,沒有下一步彼硫。

  2. 創(chuàng)建AssetManager炊豪,并接著添加系統(tǒng)資源文件路徑到資源目錄(mAssetPaths)中凌箕。

  3. 添加訪問的APK文件(當前APK文件)路徑到資源目錄(mAssetPaths)中。

  4. 創(chuàng)建Resources對象词渤,并返回陌知。

3.2、第7步:addAssetPath

在前面的分析中可知掖肋,通過調用addAssetPath方法將資源文件路徑添加到資源目錄中仆葡,實現(xiàn)資源的加載。該方法的主要內容有:

8.png

由上可知志笼,addAssetPath主要是將資源文件路徑添加到資源目錄mAssetPaths中沿盅,并且判斷添加的apk文件是否位于/system/framework/下,如果是則會在/Vendor/overlay/frame/目錄下查找是否有同名的apk文件纫溃,有的話則用該apk文件覆蓋原有apk腰涧。(該機制一般用于廠商自定義資源覆蓋系統(tǒng)資源)。

4紊浩、總結

由上分析可知窖铡,ContextImpl創(chuàng)建過程中,會調研getResources()獲得Resources對象坊谁,而getResources最后調用getTopLevelResources方法费彼。getTopLevelResources方法首先從緩存中拿Resources對象,沒有拿到則先創(chuàng)建AssetManager對象口芍,并通過AssetManager的addAssetPath實現(xiàn)系統(tǒng)資源文件箍铲、當前APK資源文件的加載,然后再創(chuàng)建Resources對象返回鬓椭。

5颠猴、后記

在andorid插件化機制中,關于如何訪問插件資源⌒∪荆現(xiàn)在的一般做法是通過反射拿到AssetManager的addAssetPath方法翘瓮,將插件資源路徑添加到資源目錄mAssetPath中,然后在創(chuàng)建Resources對象裤翩。

而另外一種方案則來自于DroidPlugin機制资盅,該插件化機制采用Hook思想,當啟動插件Activity時岛都,先替換啟動的插件Activity為代理Activity律姨,再在H的消息處理中替換回插件Activity振峻。而在H的消息處理中替換回插件Activity時臼疫,首先通過插件Acitivity信息創(chuàng)建LoadedAPK對象(指定資源路徑為插件路徑),再調用LoadedAPK的makeApplication創(chuàng)建插件Application扣孟。而關于makeApplication調用上面已經講過了烫堤,它會調用ContextImpl創(chuàng)建過程實現(xiàn)插件Resources的創(chuàng)建以及資源加載。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鸽斟,隨后出現(xiàn)的幾起案子拔创,更是在濱河造成了極大的恐慌,老刑警劉巖富蓄,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩燥,死亡現(xiàn)場離奇詭異,居然都是意外死亡立倍,警方通過查閱死者的電腦和手機灭红,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來口注,“玉大人变擒,你說我怎么就攤上這事∏拗荆” “怎么了娇斑?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長材部。 經常有香客問我毫缆,道長,這世上最難降的妖魔是什么乐导? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任悔醋,我火速辦了婚禮,結果婚禮上兽叮,老公的妹妹穿的比我還像新娘芬骄。我一直安慰自己,他們只是感情好鹦聪,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布账阻。 她就那樣靜靜地躺著,像睡著了一般泽本。 火紅的嫁衣襯著肌膚如雪淘太。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天规丽,我揣著相機與錄音蒲牧,去河邊找鬼。 笑死赌莺,一個胖子當著我的面吹牛冰抢,可吹牛的內容都是我干的。 我是一名探鬼主播艘狭,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼挎扰,長吁一口氣:“原來是場噩夢啊……” “哼翠订!你這毒婦竟也來了?” 一聲冷哼從身側響起遵倦,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尽超,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后梧躺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體似谁,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年掠哥,在試婚紗的時候發(fā)現(xiàn)自己被綠了棘脐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡龙致,死狀恐怖蛀缝,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情目代,我是刑警寧澤屈梁,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站榛了,受9級特大地震影響在讶,放射性物質發(fā)生泄漏。R本人自食惡果不足惜霜大,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一构哺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧战坤,春花似錦曙强、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至囊卜,卻和暖如春娜扇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背栅组。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工雀瓢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玉掸。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓刃麸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親排截。 傳聞我的和親對象是個殘疾皇子嫌蚤,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容