Atlas框架源码简要分析(下)–Bundle资源处理
在上文中以启动一个在没有安装的Bundle中的Activity为例,整理了整个Bundle安装到该Activity对象实例化出来的过程,当该Bundle安装之后,对应的BundleClassLoader实例化完成之后,在<中>2.10.2处会对Bundle中的资源进行处理。我们下面就对资源的处理步骤详细展开
对于系统对资源的管理可以参考:http://blog.csdn.net/luoshengyang/article/details/8738877
1.1 重新贴出Bundle资源处理的入口代码如下:
1.1.1 此处为Bundle中资源处理的入口点,处理的根本思路就是想办法把该Bundle安装位置信息(即资源路径)添加到系统的资源查找路径列表中去
DelegateResources.addBundleResources()中第一个参数是,当前Bundle当前版本解压之后所在的位置,也就是资源文件所在的位置,第二个参数是Patch文件的位置。
@BundleLifecycleHandler.java
private void loaded(Bundle bundle) {//在BundleImpl建立之后,此时bundle解压的位置,及其中的ClassLoader已经初始化完毕,则会发送CMD=0的指令到达bundleChanged,进而调用此处开始:资源加载起始点
BundleImpl b = (BundleImpl) bundle;
try {
DelegateResources.addBundleResources(b.getArchive().getArchiveFile().getAbsolutePath(),
b.getArchive().getCurrentRevision().getDebugPatchFilePath());//-------1.1.1 DelegateResources的addBundleResource(),添加当前bundle的资源到系统中去
} catch (Exception e) {
e.printStackTrace();
}
}
.....//省略代码
}
1.2 调用DelegateResources添加当前bundle中的资源到系统中,具体代码和简要逻辑如下,(此处的debug资源也包括更新的patch资源)
@DelegateResource.java
//代理资源类,该方法相当于一个工具方法,此处的RuntimeVariables.delegateResources 是在Atlas启动之后即赋值的最初默认值为主bundle的Resource
public static void addBundleResources(String assetPath,String debugPath) throws Exception{
synchronized (DelegateResources.class) {
if(debugPath!=null && !findResByAssetIndexDescending()){//------1.2.1此处主要兼容SDK20的查找方式不同,以确定debug包中的资源是否在实际资源之前加载
updateResources(RuntimeVariables.delegateResources, debugPath, BUNDLE_RES);
}
updateResources(RuntimeVariables.delegateResources, assetPath, BUNDLE_RES);//------1.2.2更新一开始一同默认的resource,主要是把当前bundle的资源路径,通过反射添加到原有resource的路径上去,**各bundle在打包时,资源对应的id是打包为一个R文件的,里面记录的是对应资源的序列号,此处需要再看怎么根据这个号找到具体位置的**
if(debugPath!=null && findResByAssetIndexDescending()){//------1.2.3 添加debug资源的路径
updateResources(RuntimeVariables.delegateResources, debugPath, BUNDLE_RES);
}
}
}
1.2.1 处主要兼容SDK20的资源查找方式不同,以确定debug包中的资源是否在实际资源之前加载
在SDK>20版本中资源查找的方式是按照资源路径列表降序查找的,也就是说后加入的路径会先去查找,而我们的debug资源目的是想要后查找,即先去正常资源中查找然后没有再到debug的资源中去查找,所以在SDK>20的版本中即findResByAssetIndexDescending()为true时就先执行跳过该步骤,先执行1.2.2添加正常的资源路径,否则就先执行此处代码添加debug的资源
- 总之就是保证在查找资源时先从该Bundle的正常资源路径中找然后再到debug的资源路径中去查找
1.2.2 处理我们bundle的资源路径
该处的RuntimeVariables.delegateResources 是在Atlas启动之后即赋值的最初默认值为主bundle的Resource,也就是系统生成的那一份resource,显然该使用该resource,我们是找不到bundle中的资源的,应为其默认的搜索路径是apk安装包位置
该处的assetPath就是我们前面传入的b.getArchive().getArchiveFile().getAbsolutePath()即当前bundle解压之后的路径
1.2.3 此处和1.2.1处对应如果1.2.1处不执行则在此处执行debug中的资源处理
1.3 bundle资源更新处理,接上面1.2.2处逻辑,该处及最终处理资源的逻辑,分别处理了Resource中的AssetManager,然后处理Resource。展开其逻辑及代码如下
@DelegateResource.java
private static void updateResources(Resources res,String assetPath,int assertType) throws Exception{//更新当前Resource中资源路径集合,把新加入的bundle资源路径添加进去
if(sAssetManagerProcessor==null){
sAssetManagerProcessor = new AssetManagerProcessor();//-------1.3.1DelegateResource 的内部类里面有自己保存的一份资源列表
}
AssetManager updatedAssetManager = sAssetManagerProcessor.updateAssetManager(res.getAssets(), assetPath, assertType);//-------1.3.2更新AssetManager,此处只是更新AssetManager,然后我们需要把代理过的新的Manager重新给放入到Resource中去
if(sResourcesProcessor==null){
sResourcesProcessor = getResourceProcessor();//------1.3.3拿取ResourceProcessor
}
sResourcesProcessor.updateResources(updatedAssetManager);//-------1.3.4更新Resource中的AssetsManager为我们代理的AssetsManager
if(sResourcesFetcher==null){
sResourcesFetcher = new ResourceIdFetcher();
}
}
1.3.1 如果sAssetManagerProcessor为null则初始化AssetManagerProcessor,该类来处理系统当前的AssetManager,初始化代码如下:
@AssetManagerProcessor.java
private static class AssetManagerProcessor {
private static HashMap<String,Boolean> sDefaultAssetPathList ;
static {
try {
AssetManager manager = AssetManager.class.newInstance();
ArrayList<String> defaultPaths = getAssetPath(manager);
if(defaultPaths!=null && defaultPaths.size()>0){
sDefaultAssetPathList = new HashMap<String,Boolean>();
for(String path : defaultPaths){
sDefaultAssetPathList.put(path,Boolean.FALSE);
}
}
}catch (Throwable e){}finally {
if(sDefaultAssetPathList==null){
sDefaultAssetPathList = new HashMap<String,Boolean>(0);
}
}
}
private LinkedHashMap<String,Boolean> assetPathCache = null;
private LinkedHashMap<String,Boolean> preAssetPathCache = null;
public AssetManagerProcessor(){
assetPathCache = new LinkedHashMap<String,Boolean>();
preAssetPat