这是Android Apk源加载机制原理分析以及动态加载实现系列文章 的最后一篇。经过前两篇的介绍之后,相关基础都讲的差不多了,现在要实现自己项目中的资源加载框架,这里提供两种方式,区别在于由谁来加载资源。
- 1、利用系统加载资源Apk
- 2、主动手动实现资源的加载
利用系统加载资源Apk
如果看了我的前两篇对系统资源加载机制分析的文章,这种方式很容易联想到。既然系统有一套成熟的资源加载机制,并经过分析完全可以独立出来,并且还很简单。从前两篇文章中很容易看到系统加载资源主要就是靠AssetManager类来实现,再通过Resources来加载具体的资源,以及Activity中的资源加载都是转由mBase(ContextImpl)来完成的,那么动态加载的话,我们就可以不利用mBase,重写ContextWrapper的获取Asset和Resources方法:
public class ContextWrapper extends Context {
Context mBase;
....
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public Resources getResources() {
return mBase.getResources();
}
.....
}
直接在Activity中覆盖这两个方法的实现,让资源获取都转到自己单独加载的Resource中,实现如下:
public class DynamicResourcesActivity extends Activity{
....
AssetManager mLocalAssetManager ;
Resources mLoacalResources ;
@Override
public AssetManager getAssets(){
return mLocalAssetManager ;
}
@Override
public Resources getResources(){
return mLoacalResources ;
}
....
}
接下来就是要实现加载动态资源的AssetManager和Resources即上文的mLocalAssetManager 和mLoacalResources ,代码如下:
privated void loadResources() {
try {
mLocalAssetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, mDexPath);
mAssetManager = assetManager;
} catch (Exception e) {
e.printStackTrace();
}
Resources superRes = super.getResources();
mLoacalResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
superRes.getConfiguration());
mTheme = mLoacalResources .newTheme();
mTheme.setTo(super.getTheme());
}
Android App启动时Apk资源加载机制源码分析中就介绍了资源Apk的加载就是通过addAssetPath来实现的,但这个方法是隐藏的,故利用反射方式。
这样就可以通过DynamicResourcesActivity 来动态加载Apk资源了。这种方式简单快捷,但是也有缺陷,必须要维护AssetManager以及Resources,对于的资源是一个res目录或者zip文件,必须由aapt工具来对资源打包编译,不够灵活,需要资源id,如果res布局文件下,仅仅是手动布局,简单加载少数资源。那就有另一种方式主动加载任意
目录下的文件。
主动手动实现资源的加载
在Res目录下资源如图片文件和xml文件资源如何被加载显示出来中提到过图片的加载实际上就是获取了对应数据字节流,以及xmL资源是解析了对应的文件内容,原理都是这样,那我们就是手动实现资源加载获取,模仿系统加载机制需要如下方面工作:
1、Drawable缓存机制
为了加快和节省内存2、图片文件以及其他资源读取数据
读取流数据以及xml文件解析利用Drawable类对资源数据处理
若是Xml文件通过 Drawable.createFromXml(wrapper, rp, theme)
来实现,而对于图片就是通过mAssets即AssetManager直接获取对应的图片的字节流然后通过
Drawable.createFromResourceStream(wrapper, value, is, file, null)
转成Drawable对象。3、根据当前分辨率显示资源并适配
这种方式对于适配不同分辨率下就麻烦点,刚开始都是用大图片来适配小图片。其实也可以模拟不同分辨率文件来分开加载不同图片。
总结
两种方式均用到项目中去,如果仅仅是简单的替换资源,且内容不多的话就可以直接用第二种方式,第一种对于动态加载框架来说很有用的。