簡 錄
概括[1]
資源分類
資源打包自定義資源ID的取值范圍[2]
使用場景
自定義方式Android資源管理器AssetManager的創(chuàng)建過程[3]
上下文環(huán)境解析
多個APK環(huán)境下資源的存儲方式
AssetsManger和Resources如何實現(xiàn)資源訪問的Android-Framework-Plugin插件化資源創(chuàng)建[4]
概括
概括中主要講解資源的基礎(chǔ)認知及資源的打包過程和注意事項
資源分類
-
assets資源
-
res資源 > res目錄下的資源會被賦予ID.方便我們通過ID訪問資源
- animator -> 屬性動畫
- anim ->補間動畫
- color ->顏色資源
- drawable -> 圖片資源
- layout -> 布局資源
- menu ->菜單資源
- raw ->任意格式資源,它同assets下資源一樣會原封不動的打入APK文件中,不過它仍會被賦予ID,我們也可以通過ID訪問它
Resources res = getResources();
InputStream is = res .openRawResource(R.raw.filename);
- values ->描述一些簡單資源
- xml ->描述應(yīng)用程序的配置信息資源
注意:
- 上述9種類型資源,除了raw類型資源和Bitmap文件的drawable類型資源外,其余的資源都將在打包過程中編譯成二進制格式的xml文件,
這些二進制文件分別有一個字符串資源池,用來保存文件中引用到的資源,
這樣做的好處
- 文件占用更小
- 解析速度更快
- Res資源在編譯完成后都會分配一個資源ID,會被保存到 R.java文件中與應(yīng)用程序的其他源文件一起編譯到程序中 ID唯一性,不唯一則出現(xiàn)資源沖突
資源打包過程
- 除了assets和res/raw資源被原封不動打進APK之外,其他資源會被編譯成二進制文件打進APK
- 除了assets資源之外,其他資源都會被賦予一個資源ID
- 打包工具完成對資源的打包和編譯后會生成一個 resources.arsc 文件和 R.java 文件,前者是 資源索引表,后者是 資源ID表
- AndroidManifest.xml同樣會被編譯成二進制的XML文件
- 應(yīng)用程序通過AssetManager來訪問資源,或通過資源ID訪問,或通過文件名訪問
自定義資源ID的取值范圍
使用場景
當(dāng)我們在插件定義的資源打包是編譯到宿主資源鏈表時,為了避免這些資源與宿主的資源沖突,所以需要我們?yōu)樗拗鞯馁Y源定義一個ID范圍.
自定以資源方式
在Android資源中,有一種資源類型稱為Public,他們一般定義在res/values/public.xml文件中芝囤,形式如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--在宿主中指定這些id的范圍是為了使宿主各類資源的id和插件各類資源的id不重復(fù),否則會出錯(若沒出錯也僅是湊巧)-->
<!-- 單獨指定屬性的資源范圍是為了支持主題屬性換膚 將end值設(shè)置為0100仆嗦,意思預(yù)留從0000到0100的id給插件屬性使用
即插件的attr不可超過256個谆甜,這個值可以根據(jù)實際情況調(diào)整
-->
<public-padding type="attr" name="public_static_final_host_attr_" start="0x7f010000" end="0x7f010100" />
<!-- 除屬性外 其他類型的資源設(shè)置為 0x7f32開始 -->
<public-padding type="drawable" name="public_static_final_host_drawable_" start="0x7f320000" end="0x7f320000" />
<public-padding type="layout" name="public_static_final_host_layout_" start="0x7f330000" end="0x7f330000" />
<public-padding type="anim" name="public_static_final_host_anim_" start="0x7f340000" end="0x7f340000" />
<public-padding type="xml" name="public_static_final_host_xml_" start="0x7f350000" end="0x7f350000" />
<public-padding type="raw" name="public_static_final_host_raw_" start="0x7f360000" end="0x7f360000" />
<public-padding type="dimen" name="public_static_final_host_dimen_" start="0x7f370000" end="0x7f370000" />
<public-padding type="string" name="public_static_final_host_string_" start="0x7f380000" end="0x7f380000" />
<public-padding type="style" name="public_static_final_host_style_" start="0x7f390000" end="0x7f390000" />
<public-padding type="color" name="public_static_final_host_color_" start="0x7f3a0000" end="0x7f3a0000" />
<public-padding type="id" name="public_static_final_host_id_" start="0x7f3b0000" end="0x7f3b0000" />
<public-padding type="bool" name="public_static_final_host_bool_" start="0x7f3c0000" end="0x7f3c0000" />
<public-padding type="integer" name="public_static_final_host_int_" start="0x7f3d0000" end="0x7f3d0000" />
<public-padding type="array" name="public_static_final_host_array_" start="0x7f3e0000" end="0x7f3e0000" />
<public-padding type="menu" name="public_static_final_host_menu_" start="0x7f3f0000" end="0x7f3f0000" />
<public-padding type="mipmap" name="public_static_final_host_mipmap_" start="0x7f400000" end="0x7f400000" />
<public-padding type="animator" name="public_static_final_host_animator" start="0x7f410000" end="0x7f410000" />
<public-padding type="fraction" name="public_static_final_host_fraction" start="0x7f420000" end="0x7f420000" />
<public-padding type="font" name="public_static_final_host_font" start="0x7f430000" end="0x7f430000" />
<public-padding type="plurals" name="public_static_final_host_plurals" start="0x7f440000" end="0x7f440000" />
<public-padding type="interpolator" name="public_static_final_host_interpolator" start="0x7f450000" end="0x7f450000" />
<public-padding type="transition" name="public_static_final_host_transition" start="0x7f460000" end="0x7f460000" />
<public-padding type="_aapt" name="public_static_final_host__aapt" start="0x7f470000" end="0x7f470000" />
</resources>
xml分析
- type 用于指定資源類型
- name 用于appt在編譯時重賦資源的name名稱,name_資源名
- start 取值起始位置
- end 取值結(jié)束位置
每當(dāng)aapt重新編譯被修改過的資源時,都會重新給這些資源賦予ID
Android資源管理器AssetManager的創(chuàng)建過程
上下文環(huán)境解析
- 每個Activity都會關(guān)聯(lián)一個ContextImpl對象,Activity和ContextImpl都繼承于Context;
- 所以Activity大部分成員函數(shù)通過都調(diào)用ContextImpl對象的對應(yīng)函數(shù)做處理的,其中訪問程序資源是通過調(diào)用ContextImpl對象的getResources()和getAssets() 函數(shù)來實現(xiàn)的
- getResources()
返回一個Resources對象纫谅,通過Resources對象我們就可以通過資源ID訪問資源
- getAssets()
返回一個AssetsManager對象,通過AssetsManager對象我們就可以通過文件名訪問被編譯過的資源文件
- 事實上Resources也是通過AssetsManager來訪問資源文件的,只不過它會先通過資源ID查找到資源文件名
多個APK環(huán)境下資源的存儲方式
Android系統(tǒng)允許一個進程中存在多個apk文件,每個APK文件都會有一個全局的Resources對象和AssetsManager對象,
- 全局的Resources對象存儲在對應(yīng)的ContextImpl對象的成員變量mResources中
- 全局的AssetsManager對象存儲在對應(yīng)的Resources對象的成員變量mAssets中
AssetsManger和Resources如何實現(xiàn)資源訪問的
Resources訪問資源
- Resources類中的成員函數(shù)getAssets(),通過getAssets()可以獲取Resources類中成員變量mAssets的AssetsManager對象,所以訪問資源最終實現(xiàn)仍在AssetsManager實現(xiàn)的
AssetsManager訪問資源
- 1.AssetsManager類除了Java層的實現(xiàn)外,還有C++層對應(yīng)的實現(xiàn)。而Java層的AssetsManager類的功能就是通過C++層來實現(xiàn)的;
- 2.Java層每個AssetsManager對象都有一個int類型的成員變量mObject,mObject保存的便是在C++層對應(yīng)的AssetsManager對象地址.
- 3.通過mObject這個變量可以將Java層對象和C++層對象關(guān)聯(lián)起來
- 4.C++層的AssetsManager類有三個重要的成員變量
- mAssetPaths -> 資源存放目錄
- mResources -> 指向一個資源索引表,以供Resources對象通過資源ID訪問資源
- mConfig -> 設(shè)備的本地配置信息,包括屏幕的密度和大小、國家地區(qū)勾拉、語言等
有了這三個變量后,C++層的AssetsManager類就可以訪問程序資源了
Android-Framework-Plugin插件化資源創(chuàng)建
- 1.創(chuàng)建一個AssetManager的代理類的實例,因為是對AssetManager做代理,所以需要將AssetManasger的實例傳入到代理中
HackAssetManager hackAssetManager = new HackAssetManager(assetMgr);
- 2.在HackAssetManager中通過反射將assetPaths數(shù)組中的資源路徑添加進去
hackAssetManager.addAssetPaths(assetPaths);?
- 3.完成以上步驟后我們需要創(chuàng)建字符串資源池來實現(xiàn)資源的添加
hackAssetManager.ensureStringBlocks(); //創(chuàng)建字符串資源池
4.現(xiàn)在我們可以獲取資源了
?Resources pluginRes = new PluginResourceWrapper(assetMgr, mainRes.getDisplayMetrics(),mainRes.getConfiguration(), pluginDescriptor);
// assetMgr 是我們?nèi)诤虾蟮腁sset資源
?//mainRes 是宿主的Resources實例,調(diào)用了其中的兩個屬性方法
//pluginDescriptor 是插件的??屬性數(shù)據(jù)序列化類實例?
//通過實例化此得到一個Resources資源實例,?
具體的實現(xiàn)代碼請移步Android-Fragmework-Plugin,GitHub地址