我们知道,activity的工作主要是由ContextImpl来完成的, 它在activity中是一个叫做mBase的成员变量。注意到Context中有如下两个抽象方法,看起来是和资源有关的,实际上context就是通过它们来获取资源的,这两个抽象方法的真正实现在ContextImpl中。也即是说,只要我们自己实现这两个方法,就可以解决资源问题了。
/** Return an AssetManager instance for your application’s package. */
public abstract AssetManager getAssets();
/** Return a Resources instance for your application’s package. */
public abstract Resources getResources();
下面看一下如何实现这两个方法
首先要加载apk中的资源:
[java] view plain copy
-
protected void loadResources() {
-
try {
-
AssetManager assetManager = 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();
-
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();
学习福利
【Android 详细知识点思维脑图(技能树)】
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
[外链图片转存中…(img-QnUJTqiS-1714684003586)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!