说到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 {
mgr.attachApplication(mAppThread, startSeq);//作用在于将mAppThread传递到AMS进程去,最后在AMS的attachApplicationLocked方法中会调用mAppThread的bindApplication方法
} 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的:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
appContext.setOuterContext(activity);
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);
}
}
其创建管理过程基本和Application相似。在类推一下Service估计也是一样,事实也是如此:
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
}
try {
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);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
}
}
Android四大组件其中Activity和Service由于本身就是Context的子类并且在创建的时候又各自关联了ContextImpl,因此他们自身都是存在Context上下文的。
获取各种Context
最常见的方法就是通过this指针,当我们在Activity中,我们就可以通过this,来获取Activity的上下文Context,并且干点事情。这是最简单的获取Context的方式,Android还提供了一些其他的接口用来获取各种类型的Context。比如:getBaseContext(顾名思义,获取mBase所指的ContextImpl对象),getApplicationContext(获取的Application对象),getApplication(Activity和Service中有,获取所属的Application对象)。
写在最后
本篇文章在于讲解Android中Context的设计实现,以及初步了解Android中是如何创建使用Context,并未过多的涉及Context的使用,以及使用Context某个方法时深究其中的原理,这些都留于后面详细分析Android再一一讲解其中的原理实现。大家如果有兴趣也可以自行阅读源码。