转载请注明出处:http://blog.csdn.net/ximsfei/article/details/51063454
github地址:https://github.com/ximsfei/DynamicDeploymentApk
在上一篇文章:Android动态部署三:如何从插件apk中启动Activity(-)中分析了Activity的启动流程以及从插件apk中启动一个Activity时所需要关注的源码细节,相信读者已经自己去尝试过从插件apk中启动Activity了,也可能已经遇到了我们这篇文章所要讲的问题。
接下来我们会接着上一篇文章中我的猜想, 来详细分析一下为什么我们需要替换Context, Resources, AssetManager, Theme, Title, Application等信息。
替换Context
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
...
}
public class Activity extends ContextThemeWrapper;
public class ContextThemeWrapper extends ContextWrapper;
public class ContextWrapper extends Context;
Activity 继承自ContextWrapper类,并且在attach方法中会调用到ContextWrapper类中的attachBaseContext方法,将ContextImpl实例保存到ContextWrapper的成员变量mBase中。
在ContextWrapper类中我们了解到原来Activity中真正的Context实现为ContextImpl类而ContextImpl中所保存的信息还是宿主apk中的上下文信息,Resources,AssetManager,ClassLoader等等,这些都是跟apk中的资源以及源文件息息相关的,所以想要在插件Activity中使用插件资源,源文件,我猜想需要将ContextImpl中的信息替换成插件apk的ContextImpl。我们不妨参照源码Activity的实现方式,来实现我们自己的DynamicContextImpl类:
DynamicContextImpl.java
public class DynamicContextImpl extends ContextWrapper {
private final Resources mResources;
private final AssetManager mAssets;
private final ClassLoader mClassLoader;
private final String mPackageName;
private final int mThemeResource;
private final Application mApplication;
private Resources.Theme mTheme;
private DynamicContextImpl(Context hostContext, DynamicApkInfo apkInfo, int themeResource) {
super(hostContext);
mThemeResource = themeResource;
mResources = apkInfo.resources;