《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
完整开源地址:https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF
-
addAssetPath.invoke(assetManager, mDexPath);
-
mAssetManager = assetManager;
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
Resources superRes = super.getResources();
-
mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
-
superRes.getConfiguration());
-
mTheme = mResources.newTheme();
-
mTheme.setTo(super.getTheme());
-
}
说明:加载的方法是通过反射,通过调用AssetManager中的addAssetPath方法,我们可以将一个apk中的资源加载到Resources中,由于addAssetPath是隐藏api我们无法直接调用,所以只能通过反射,下面是它的声明,通过注释我们可以看出,传递的路径可以是zip文件也可以是一个资源目录,而apk就是一个zip,所以直接将apk的路径传给它,资源就加载到AssetManager中了,然后再通过AssetManager来创建一个新的Resources对象,这个对象就是我们可以使用的apk中的资源了,这样我们的问题就解决了。
[java] view plain copy
-
/**
-
* Add an additional set of assets to the asset manager. This can be
-
* either a directory or ZIP file. Not for use by applications. Returns
-
* the cookie of the added asset, or 0 on failure.
-
* {@hide}
-
*/
-
public final int addAssetPath(String path) {
-
int res = addAssetPathNative(path);
-
return res;
-
}
其次是要实现那两个抽象方法
[java] view plain copy
-
@Override
-
public AssetManager getAssets() {
-
return mAssetManager == null ? super.getAssets() : mAssetManager;
-
}
-
@Override
-
public Resources getResources() {
-
return mResources == null ? super.getResources() : mResources;
-
}
okay,问题搞定。这样一来,在apk中就可以通过R来访问资源了。
这是本文开头提到的另一个需要解决的难题。为什么会有这个问题,其实很好理解,apk被宿主程序调起以后,apk中的activity其实就是一个普通的对象,不具有activity的性质,因为系统启动activity是要做很多初始化工作的,而我们在应用层通过反射去启动activity是很难完成系统所做的初始化工作的,所以activity的大部分特性都无法使用包括activity的生命周期管理,这就需要我们自己去管理。谈到activity生命周期,其实就是那几个常见的方法:onCreate、onStart、onResume、onPause等,由于apk中的activity不是真正意义上的activity(没有在宿主程序中注册且没有完全初始化),所以这几个生命周期的方法系统就不会去自动调用了。针对此类问题,采用Fragment是一个不错的方法,Fragment从3.0引入,通过support-v4包,可以兼容3.0以下的android版本。Fragment既有类似于Activity的生命周期,又有类似于View的界面,将Fragment加入到Activity中,activity会自动管理Fragment的生命周期,通过第一篇文章我们知道,apk中的activity是通过宿主程序中的代理activity启动的,将Fragment加入到代理activity内部,其生命周期将完全由代理activity来管理,但是采用这种方法,就要求apk尽量采用Fragment来实现,还有就是在做页面跳转的时候有点麻烦,当然关于Fragment相关的内容我将在后面再做研究,本文不采用Fragment而是通过反射去手动管理activity的生命周期。
我们要在代理activity中去反射apk中activity的所有生命周期的方法,然后将activity的生命周期和代理activity的生命周期进行同步。首先,反射activity生命周期的所有方法,还反射了onActivityResult这个方法,尽管它不是典型的生命周期方法,但是它很有用。
[java] view plain copy
-
protected void instantiateLifecircleMethods(Class<?> localClass) {
-
String[] methodNames = new String[] {
-
“onRestart”,
-
“onStart”,
-
“onResume”,
-
“onPause”,
-
“onStop”,
-
“onDestory”
-
};
-
for (String methodName : methodNames) {
-
Method method = null;
-
try {
-
method = localClass.getDeclaredMethod(methodName, new Class[] { });
-
method.setAccessible(true);
-
} catch (NoSuchMethodException e) {
-
e.printStackTrace();
-
}
-
mActivityLifecircleMethods.put(methodName, method);
-
}
-
Method onCreate = null;
-
try {
-
onCreate = localClass.getDeclaredMethod(“onCreate”, new Class[] { Bundle.class });
-
onCreate.setAccessible(true);
-
} catch (NoSuchMethodException e) {
-
e.printStackTrace();
-
}
-
mActivityLifecircleMethods.put(“onCreate”, onCreate);
-
Method onActivityResult = null;
-
try {
-
onActivityResult = localClass.getDeclaredMethod(“onActivityResult”,
-
new Class[] { int.class, int.class, Intent.class });
-
onActivityResult.setAccessible(true);
-
} catch (NoSuchMethodException e) {
-
e.printStackTrace();
-
}
-
mActivityLifecircleMethods.put(“onActivityResult”, onActivityResult);
-
}
其次,同步生命周期,主要看一下onResume和onPause,其他方法是类似的。看如下代码,很好理解,就是当系统调用代理activity生命周期方法的时候,就通过反射去显式调用apk中activity的对应方法。
[java] view plain copy
-
@Override
-
protected void onResume() {
-
super.onResume();
-
Method onResume = mActivityLifecircleMethods.get(“onResume”);
-
if (onResume != null) {
-
try {
-
onResume.invoke(mRemoteActivity, new Object[] { });
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
nResume != null) {
-
try {
-
onResume.invoke(mRemoteActivity, new Object[] { });
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}