在上篇文章《设计模式之装饰模式》中咱们谈到了装饰模式,在 Android 中关于 Context 的设计就用到了装饰模式。这篇文章咱们就来聊一聊 Context。java
关于 Context,做为 Android 开发人员再熟悉不过了。启动 Actiivty、Service 须要 Context,获取资源须要 Context。离开 Context 整个系统都玩不转了,可见 Context 在 Android 中多么重要。android
先来回忆一下上篇文章中装饰模式的结构图设计模式
再来对比一下 Context 的继承结构图 bash
看着这两张图咱们来找一下对应关系微信
Componment -> Contextapp
ConcreteComponment -> ContextImpl框架
Decorator -> ContextWrapperide
ConcreteDecorator -> ContextThemeWraper、Activity、Service、Applicationui
再来具体看一下代码this
Context.java
public abstract void startActivity(@RequiresPermission Intent intent);
public abstract ComponentName startService(Intent service);
public abstract Resources getResources();
复制代码
Context 是一个抽象类,定义了咱们经常使用的大部分抽象方法。
ContextImpl.java
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
复制代码
@Override
public void startActivity(Intent intent, Bundle options) {
//省略代码
//启动activity的入口
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
复制代码
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
复制代码
ContextImpl 是 Context 的具体实现,也就是咱们实际使用的对象。
ContextWrapper.java
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
// 省略代码
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
}
复制代码
ContextWrapper 这个类比较简单,里面有一个 Context(mBase) 的引用,也就是 ContextImpl 类的对象。还有一个 attachBaseContext 方法下面会提到。是给引用的 ContextImpl(mBase)赋值的地方。下面咱们看下 ContextImpl 这个对象是何时建立和赋值给 mBase 的。
要理解 ContextImpl 是如何建立的就不得不提到 Activity、Service、Application 的建立流程,因为涉及的代码比较多,咱们只看关键部分。
主要分析 ActivityThread 这个类,看一下 performLaunchActivity 方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
// 省略代码
//在这里建立了ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
if (activity != null) {
// 这个方法参数不少,如今咱们只关心第一个appContext
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
if (customIntent != null) {
activity.mIntent = customIntent;
}
// 省略代码
r.activity = activity;
}
// 省略代码
return activity;
}
复制代码
Activity 建立关键代码,注意 attach 这个方法
Activity.java
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,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
// 省略代码
}
复制代码
看到这能够发现,在 attach 方法中,第一个参数 appContext 也就是 ContextImpl 类的对象,在 attach 方法中又调用了 ContextWrapper 的attachBaseContext(context),最终把 appContext 赋值给 mBase。
Service建立关键代码
private void handleCreateService(CreateServiceData data) {
// 省略代码
Service service = null;
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// 省略代码
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
// 省略代码
}
复制代码
Service.java
关键代码
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
// 省略代码
}
复制代码
能够看到,一样是在 attach 方法中,经过调用 attachBaseContext(context) 把 ContextImpl 的对象赋值给了 mBase。其余的建立过程再也不分析,有兴趣能够了解下 ActivityThread 源码。至此整个过程就串起来了,这就是装饰模式在 Context 中的实现。
最后再来看一下 RePlugin 中 PluginContext 和 HostContext 是如何获取的,直接上代码。
RePlugin.java
// 获取插件的Context
public static Context getPluginContext() {
return RePluginEnv.getPluginContext();
}
// 获取宿主的Context
public static Context getHostContext() {
return RePluginEnv.getHostContext();
}
复制代码
能够看到两个方法都是调用了 RePluginEnv 中的方法,再去看下 RePluginEnv 的代码
RePluginEnv.java
// 获取插件的Context
public static Context getPluginContext() {
return sPluginContext;
}
// 获取宿主的Context
public static Context getHostContext() {
return sHostContext;
}
复制代码
以上两个 Context 都是在 init 方法中赋值的。
static void init(Context context, ClassLoader cl, IBinder manager) {
sPluginContext = context;
// 确保获取的必定是主程序的Context
sHostContext = ((ContextWrapper) context).getBaseContext();
}
复制代码
再往下看, init 方法是在 Entry 的 create 方法调用。
Entry.java
public class Entry {
public static final IBinder create(Context context, ClassLoader cl, IBinder manager) {
// 初始化插件框架
RePluginFramework.init(cl);
// 初始化Env
RePluginEnv.init(context, cl, manager);
return new IPlugin.Stub() {
@Override
public IBinder query(String name) throws RemoteException {
return RePluginServiceManager.getInstance().getService(name);
}
};
}
}
复制代码
Entry 的 create 又是在 Loader.java
中经过反射调用的,看下代码
Loader.java
mPkgContext = new PluginContext(mContext, android.R.style.Theme, mClassLoader, mPkgResources, mPluginName, this);
复制代码
IBinder b = (IBinder) mCreateMethod2.invoke(null, mPkgContext, getClass().getClassLoader(), manager);
复制代码
能够看到, create 方法的第一个参数就是 mPkgContext(PluginContext对象),它就是插件的 Context,有本身的 classloader 和 resource。同时 PluginContext 的构造方法接受一个 Context,也就是宿主的 Context,它也就是mBase
。因此在上面的代码中就能够拿到宿主的 sHostContext 了。
sHostContext = ((ContextWrapper) context).getBaseContext();
复制代码
至此,RePlugin 插件中获取的宿主和插件 Context 分析完毕。