参考:http://blog.youkuaiyun.com/yulong0809/article/details/59489396
插件化:加载资源
1、LoadedApk是一个apk在内存中的标示, Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等四大组件的信息我们都可以通过此对象获取;
2、LoadedApk 创建的时候会传入一个ApplicationInfo的对象,也就是说我们插件中使用的资源,其实用的是宿主的资源库,然而宿主的资源库并没有插件的资源,所以肯定会报错;
3、我们使用资源的时候,一般都是通过R.或者Context.getResources(),而R.也是通过Context.getResources()获取id的。看Context的视线类ContextImpl的源码
4、getResources()返回的是Resources对象:mResouces;看一下mResources是怎么创建的?
5、在ContextImpl的构造方法中创建了mResources,mResources是通过ResourcesManager创建的: mResources = mResourcesManager.getTopLevelResources()
6、ResourcesManager.getTopLevelResources()主要通过3步来得到Resources对象的:
a.创建AssetManager对象:AssetManager assets = new AssetManager();
b.通过assets.addAssetPath(resDir)方法给AssetManager添加资源路径;
c.通过AssetManager来创建一个Resources对象。
加载资源的思路:
1、给插件apk创建一个属于自己的Resources对象;
2、插件apk默认拿的是宿主的Resources对象,所以得在宿主中提供一个返回插件apk自己资源的方法;
3、在插件apk中我们要重写Context的getResource方法
总结:就是在宿主中构造好插件的资源,然后提供一个获取资源的方法,然后在插件中用资源的时候,掉用宿主提供的方法。
实现
都写在Application这个类中了:
public class MyApplication extends Application {
private static Context sContext;
private AssetManager assetManager;
private Resources newResource;
private Resources.Theme mTheme;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
sContext = base;
try {
//创建我们自己的Resource
//这是插件apk的路径
String apkPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/demo.apk";
assetManager = AssetManager.class.newInstance();
Method addAssetPathMethod = assetManager.getClass().getDeclaredMethod("addAssetPath", String.class);
addAssetPathMethod.setAccessible(true);
addAssetPathMethod.invoke(assetManager, apkPath);
Method ensureStringBlocks = AssetManager.class.getDeclaredMethod("ensureStringBlocks");
ensureStringBlocks.setAccessible(true);
ensureStringBlocks.invoke(assetManager);
Resources supResource = getResources();
Log.e("Main", "supResource = " + supResource);
newResource = new Resources(assetManager, supResource.getDisplayMetrics(), supResource.getConfiguration());
Log.e("Main", "设置 getResource = " + getResources());
mTheme = newResource.newTheme();
mTheme.setTo(super.getTheme());
} catch (Exception e) {
Log.e("Main", "走了我的callActivityOnCreate 错了 = " + e.getMessage());
e.printStackTrace();
}
}
@Override
public AssetManager getAssets() {
return assetManager == null ? super.getAssets() : assetManager;
}
@Override
public Resources getResources() {
return newResource == null ? super.getResources() : newResource;
}
@Override
public Resources.Theme getTheme() {
return mTheme == null ? super.getTheme() : mTheme;
}
public static Context getContext() {
return sContext;
}
}