Android资源加载流程及资源替换方案

来源于慕课网。

1 资源加载流程

我们所说的资源是指assets,res目录下的drawable,layout,color,string,id等等,obtainStyledAttributes。方法调用都是从context到Resources,最后到AssetManager。然后在NativeAssetManager里处理。见图。
Android资源加载流程及资源替换方案

2 资源替换方案

从资源加载流程可以发现,替换方案从Resources或者AssetManager下手。

2.1 资源包装流

包装Resources,当然是对其大部分方法都要包装。优先去加载我们添加进去的资源。没有找到,则去走系统的流程。是一个麻烦的过程。
Android资源加载流程及资源替换方案

2.2 资源缓存

系统Resources里获取资源时,会先从缓存里获取,获取不到则去AssetManager里找。所以可以通过反射将要加载的资源添加进缓存。这样的过程很明显受限于系统缓存的内容,而且由于不同的版本字段会有所变化,适配过程繁琐。
Android资源加载流程及资源替换方案

2.3 AssetManager

这是一种系统的加载方案,总的来说,支持的文件种类最多。
相关连接

该方案使用反射拿到AssetManager里的addAssetPath方法,添加apk路径。这样也会有很多坑,对不同的版本需要进行适配。在创建完activity,也需要将处理好的mResources设置进Context中。

Android资源加载流程及资源替换方案

2.4 方案对比

Android资源加载流程及资源替换方案

3 资源冲突问题

换肤和插件处理资源冲突问题是不一样的。换肤是要覆盖原来的ID的,而插件可能要并存。
换肤资源冲突问题:
1.资源重定向问题
使用动态映射方案:根据ID找到名称,然后根据名称和包名找到对应的资源ID。
静态编译方案:1.aapt编译资源时输入主包的资源ID映射,public.xml;
2.编译后根据主包映射关系修改皮肤包的resources.arsc .
静态编译方案的问题:资源增量静态对齐。资源查找过程中会有一个资源个数判断,所以需要让皮肤包的资源至少大于等于主包的资源数量,不足的部分使用占位资源。
第二个问题是,资源删除后如果不用占位资源,由于资源编排紧凑的这种方式,其他资源会排到删除的资源位置,这样查找的资源就会出错。这里也需要使用占位资源。

VirtualApk使用Gradle插件处理
具体思路如下:
根据编译产生的R.txt文件收集插件中所有的资源
过滤插件资源: 过滤掉在宿主中已经存在的资源
重新设置插件资源的资源ID
删除掉插件资源目录下前面已经被过滤掉的资源
重新编排插件: 修改resources.arsc文件中插件资源ID为新设置的资源ID
重新产生R.java文件