尊重原创:https://blog.csdn.net/abm1993/article/details/82968235
说到Context,大家一定非常熟悉,Android中的很多操作都和Context有关,比如打开activity、发送广播、打开本包下文件夹和数据库、获取classLoader、获取资源等等。那么这个Context究竟是何方神圣,我们不得而知,仅仅止步于如何使用Context,本篇将和大家一起聊聊Android中的Context。
首先我们先来了解装饰者模式是什么样的
装饰模式的思想是在不改变原来类文件和使用继承的情况下动态的扩展类的功能
Context架构设计
Android Context的设计完美的体现了装饰模式,装饰模式的思想是在不改变原来类文件和使用继承的情况下动态的扩展类的功能。Context就是一个抽象接口,ContextImpl是该接口的实现,而ContextWrapper就是装饰者,Application,Service等等就是更加具体的装饰者。而这些接口实现和装饰者在Android中是如何联系在一起的呢?我们继续往下分析。
创建Context
我们知道有很多操作都依赖Context,比如启动Activity,启动Service……那么这些Context是在什么时候创建的呢?ActivityThread的main函数是应用程序的入口,我们就从main函数开始分析:
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
继续看下ActivityThread的attach方法:
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
//作用在于将mAppThread传递到AMS进程去,最后在AMS的attachApplicationLocked
//方法中会调用mAppThread的bindApplication方法
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {//系统进程,暂不分析
}
}
根据分析,继续查看ApplicationThread的bindApplication方法,这里就不一一罗列代码了直接查看最终调用处理的handleBindApplication方法:
private void handleBindApplication(AppBindData data) {
long st_bindApp = SystemClock.uptimeMillis();
// Note when this process has started.
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
VMRuntime.setProcessPackageName(data.appInfo.packageName);
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//创建LoadedApk,LoadedApk就是Apk文件在内存中的表示
try {
app = data.info.makeApplication(data.restrictedBackupMode, null);//为应用创建Application
mInitialApplication = app;
try {
mInstrumentation.callApplicationOnCreate(app);//调用Application的onCreate方法
} catch (Exception e) {
}
} finally {
}
}
继续看下LoadedApk的makeApplication方法:
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
Application app = null;
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
return app;
}
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
终于守得云开见月明,终于在makeApplication看见创建ContextImpl,从Context架构设计一节中我们知道Application是一个装饰者,用来装饰谁呢?Context的实现类ContextImpl。当我们创建完Application时,此时Application中的mBase指向的就是我们通过createAppContext,其赋值的地方就是app.attach(context)。同时ContextImpl也通过设置setOuterContext与Application关联。同样的我们创建Activity和Service的时候也会创建对应的ContextImpl并且设置与ContextImpl关联。那么他们设置的关联有什么作用呢?答案肯定是有的,当我们在Activity中或者Application或者Service中或者调用某个Context的getBaseContext方法的时候,获取的便是这个ContextImp。再来看下Activity创建过程是如何管理ContextImpl的: