1、Context的概述
Context就是上下文或者场景,我们可以把它的使用场景大概分为2类:
- 1、使用Context调用方法,比如打开Activity、启动服务、获取资源。
- 2、调用方法传入Context,比如弹出吐司、弹出弹窗。
Context
是一个抽象类,它内部定义了很多静态变量和抽象方法,ContextImpl
是Context
的具体实现类,ContextWrapper
虽然继承了Context
但是具体的实现基本上全部交由其内部的成员mBase
即ContextImpl
来完成。
Application、Service、Activity都是间接继承Context
的,所以一个程序中Context
的数量==所有Activity和Service的个数加Application的个数(有几个进程就有几个Application)。下面给出Context的关系图。
Context关系图.png
- 1、
ContextImpl
和ContextWrapper
是继承Context
,但是Context
抽象方法是在ContextImp
中实现的,ContextWrapper
虽然也继承了Context
但是其中的方法的实现都交由ContextImpl
去完成的。ContextWrapper
只是ContextImpl
的包装类。 - 2、
ContextThemeWrapper
、Service
、Application
都继承了ContextWrapper
,所以它们也可以使用mBase调用Context中的方法,它们也是ContextImpl
的包装类。 - 3、
Activity
是继承ContextThemeWrapper
,从名字就能看出它是和主题相关的,所以和主题相关的Activity
是继承ContextThemeWrapper
,而和主题无关的Service
和Application
是继承ContextWrapper
。
2、Application 的Context创建过程
我们一般通过getApplicationContext()
来获取系统全局的Application Context,那么Application Context是在哪里创建的呢?
这就要从应用的启动开始,App启动会调用ActivityThread
的内部类ApplicationThread
的scheduleLaunchActivity
方法来启动
private class ApplicationThread extends ApplicationThreadNative {
...
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
...
}
在ApplicationThread
的scheduleLaunchActivity
方法中向H类
发送LAUNCH_ACTIVITY
类型的消息,目的是将启动Activity的逻辑放在主线程中的消息队列中,这样启动Activity的逻辑会在主线程中执行。在handleMessage()
中调用ActivityThreadhandleLaunchActivity()
ActivityThread##handleLaunchActivity()
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
//....
final Activity a = performLaunchActivity(r, customIntent);
//....
return a;
}
会调用performLaunchActivity()
ActivityThread##performLaunchActivity()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
//....
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//....
}
return activity;
}
这里只保留了和Application Context相关的逻辑,r.packageInfo
返回的是LoadedApk
的对象。
LoadedApk##makeApplication()
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//...
try {
//...
java.lang.ClassLoader cl = getClassLoader();
//...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//分析1
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);//分析2
appContext.setOuterContext(app);
} catch (Exception e) {
//...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;//分析3
//...
return app;
}
- 1、分析1:创建
ContextImpl
的对象,其内部直接通过new ContextImpl()
进行创建。 - 2、分析2:通过
Instrumentation
的newApplication()
创建Application
。 - 3、分析3:将
Application
赋值给LoadedApk
中的mApplication。getApplicationContext()
方法返回就是这个mApplication。
先看下创建Application
的方法
Instrumentation##newApplication()
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;
}
Application
是通过instantiateApplication()
创建的
Instrumentation##instantiateApplication()
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
@NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Application) cl.loadClass(className).newInstance();
}
可以看到最终是通过反射创建的,再回过来看下Instrumentation.newApplication()
,在Application
创建完成后调用了Application
的attach()
Application##attach()
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
里面又调用了Application
的父类ContextWrapper
的attachBaseContext(context)
ContextWrapper##attachBaseContext()
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
这样就把创建的ContextImpl
对象赋值给了ContextWapper
中的mBase
。
2.1、Application Context的创建过程

3、Application Context的获取
Application Context的是通过getApplicationContext()
返回的,
getApplicationContext()
最终的实现在ContextWrapper
中
ContextWrapper##getApplicationContext()
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
可以看到最终会调用mBase.getApplicationContext()
即ContextImpl
的getApplicationContext()
。
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
从上面分析Application Context的创建过程可知,mPackageInfo 不为null,所以会调用mPackageInfo.getApplication()
,最终会调用LoadedApk.getApplication()
LoadedApk##getApplication()
Application getApplication() {
return mApplication;
}
mApplication
在makeApplication
中已经赋值,mApplication
就是Application的实例。
4、getApplication()和getApplicationContext()
经过上面的分析可知getApplication()和getApplicationContext()返回的都是Application的实例。
既然他们返回完全一样,为什么要有这两个方法呢?
表面上的区别就是只有在Activity、Service中可以调用getApplication()
,而在其他类中却只能使用context.getApplicationContext()来获取Application的实例。更深层的原因还没想到。
网友评论