Context 意为上下文,是一个应用程序环境信息的接口
它的使用场景总的来说分为两大类:
使用 Context 调用方法,比如启动Activity、访问资源、调用系统级服务等
调用方法时传入 Context,比如弹出 Toast、创建 Dialog等
Activity、Service和Application都间接地继承自 Context,因此我们可以计算出一个应用程序进程中有多少个 Context,这个数量等于Activity和Service的总个数加1,1指的是Application的数量
Context 是一个抽象类,它的内部定义了很多方法和静态常量,它的具体实现类为 ContextImpl,ContextWrapper 则为装饰类,他们两个都继承自 Context。
ContextImpl 提供了很多功能,但是外界需要使用并扩展 ContextImpl 的功能,因此设计上使用了装饰模式,ContextWrapper 是装饰类,它对 ContextImpl 进行包装,ContextWrapper主要是起了方法传递的作用,ContextWrapper 中几乎所有的方法都是调用 ContextImpl 的相应方法来实现的
ContextWrapper 内部包含 Context 类型的 mBase 对象,mBase 具体指向 ContextImpl
Context 的关联类使用了装饰模式,主要有一下优点
使用者(比如Service)能够更方便的使用 Context
如果 ContextImpl 发生了变化,它的装饰类 ContextWrapper 不需要做任何修改
ContextImpl 的实现不会暴露给使用者,使用者也不必关心 ContextImpl的实现
通过组合而非继承的方式,扩展 ContextImpl 的功能,在运行时选择不同的装饰类,实现不同的功能
首先我们从应用程序的启动过程开始着手
ActivityThread 类作为应用程序进程的主线程管理类,它会调用它的内部类 ApplicationThread 的 scheduleLaunchActivity 方法来启动 Activity
在ApplicationThrad 的 scheduleLaunchActivity 方法中会向 H 类发送 LAUNCH_ACTIVITY类型的消息
目的是将启动 Activity 的逻辑放在主线程的消息队列中,这样启动 Activity 的逻辑会在主线程中执行
接着我们查看 H 类的 handleMessage 方法对 LAUNCH_ACTIVITY 类型消息的处理
/*frameworks/base/core/java/android/app/ActivityThread.java*/
private class H extends Handler{
...
public void handlerMessage(Message msg){
switch(msg){
case LAUNCH_ACTIVITY:
//通过 getPackageInfoNoCheck 方法获得 LoadApk 类型对象,并将该对象赋值给 ActivityClientRecord 的成员变量 packageInfo,其中 LoadApk用来描述已加载的APK文件
r.packageInfo = getPackageInfoNoCheck(r.activtiyInfo.applicationInfo, r.compatInfo);
//调用ActivityThread 的 handleLaunchActivity
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
}
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason){
...
Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
...
try{
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
}
...
return activity;
}
/*frameworks/base/core/java/android/app/LoadedApk.java*/
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation){
//如果不为nullze返回mApplication对象,这里看的是第一次启动,所以为null
if(mApplication != null){
return mApplication;
}
...
java.lang.ClassLoader cl = getClassLoader();
//创建 ContextImpl
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//创建 Application
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
//将 Application 赋值给 ContextImpl 的 Context 类型的成员变量 mOuterContext,这样 ContextImpl 中也包含了 Application 的引用
appContext.setOuterContext(app);
...
// 将 Application 赋值给 LoadedApk 的成员变量 mApplication, 用来代表 Application Context
mApplication = app;
}
//下面我们看一下 Application 是如何创建的
/*frameworks/base/core/java/android/app/Instrumentation.java*/
static public Application newApplication(Class> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
Application app = (Application) clazz.newInstance();
//通过反射来创建 Application
app.attach(context);
return app;
}
/*Application.java*/
final void attach(Context context){
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
/*ContextWrapper.java*/
protected void attachBaseContext(Context base){
if(mBase != null){
throw new IllegalStateException("Base context already set");
}
//这个base一路传递过来指的是 ContextImpl,它是 Context 的实现类,将 ContextImpl 赋值给 ContextWrapper 的 Context 类型的成员变量 mBase,而 Application 继承自 ContextWrapper ,同样可以使用 Context 的方法。
mBase = base;
}
Application 的 attach 方法的作用就是使 Application 可以使用 Context 的方法,这样 Application 才可以用来代表 Application Context
通过调用 getApplicationContext 方法来获取 Application Context,getApplicationContext 方法在 ContextWrapper 中实现
/*ContextWrapper.java*/
public Context getApplicationContext(){
//mBaser指的是 ContextImpl
return mBase.getApplicationContext();
}
/*ContextImpl.java*/
//如果 LoadApk 类型的 mPackageInfo 不为 null,则调用LoadApk的getApplication方法,否则调用ActivityThread的getApplicaiont方法
//由于应用程序已经启动,所以 LoadApk 不会为null
public Context getApplicationContext(){
return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication();
}
/*LoadApk.java*/
//这个 mApplication就是在makeApplication()方法中创建的Application
Application getApplication(){
return mApplication;
}
开始的时候和Application的创建过程相似。都是通过 ActivityThread 的内部类 ApplicationThread 来调用 scheduleLaunchActivity 方法来启动,然后在这个方法中通过sendMessage方法向 H 类发送类型为 LAUNCH_ACTIVITY 的消息,H类的handleMessage方法会对该消息进行处理,其中调用了 ActivityThread 的 handleLaunchActivity 方法,而在该方法中又会调用 performLaunchActivity
/*frameworks/base/core/java/android/app/ActivityThread.java*/
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
...
//1.创建 Activity 的 ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
java.lang.ClassLoader cl = appContext.getClassLoader();
//2.创建 Activity 的实例
activity = mInstrumentation.newActivity(cl, componetn.getClassName(), r.intent);
...
//3.将创建的Activity的实例赋值给 ContextImpl 的成员变量 mOuterContext,这样 ContextImpl 也可以访问 Activity 的变量和方法
appContext.setOuterContext(activity);
//4.将ContextImpl传入activity的attach
activity.attach(appContext, this, ...);
...
if(r.isPersistable()){
//5.该方法会调用 Activity 的 onCreate 方法
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
}
}
//接下来看一下注释1处的 createBaseContextForActivity()方法(frameworks/base/core/java/android/app/ActivityThread.java)
private ContextImpl createBaseContextForActivity(ActivityClientRecord r){
...
//该方法会调用 ContextImpl 的 createActivityContext 方法来创建 ContextImpl
ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}
//然后我们再看一下注释4处的 Activity.attach() 方法(Activity.java)
final void attach(Context context, ActivityThread aThread, Instrumentation instr,...){
attachBaseContext(context);//注释1
//创建 PhoneWindow,代表应用程序窗口。PhoneWindow 在运行中会间接触发很多事件,比如点击、菜单弹出、屏幕焦点变化等事件,这些事件需要转发给与PhoneWindow关联的Activity,转发操作通过Window.Callback接口实现,Activity实现了这个接口
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//将当前Activity通过Window的setCallback方法传递给PhoneWindow
mWindow.setCallback(this);
...
//为PhoneWindow设置WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED)!=0);
//获取 WindowManager 并赋值给 Activity 的成员变量 mWindowManager,这样在 Activity中就可以通过 getWindowManager方法来获取WindoManager
mWindowManager = mWindow.getWindowManager();
}
//下面我们来看一下注释一处的attachBaseContext 方法的实现(ContextThemeWrapper.java)
protected void attachBaseContext(Context newBase){
//父类是ContextWrapper
super.attachBaseContext(newBase);
}
//ContextWrapper.java
protected void attachBaseContext(Context base){
if(mBase != null){
throw new IllegalStateException("Base context already set");
}
//base指的是一路传递过来的 Activity 的 ContextImpl,将它赋值给 ContextWrapper的成员变量 mBase,当我们调用ContextWrapper中的方法时实际上就是调用的ContextImpl中的方法
mBase = base;
}
总结一下,在启动Activity的过程中创建 ContextImpl,并赋值给 ContextWrapper 的成员变量 mBase。Activity 继承自 ContextWrapper 的子类 ContextThemeWrapper,这样Activity中就可以使用Context中定义的方法了
Service的Context创建过程与Activity的Context创建过程相似,是在 Service 的启动过程中被创建的。ActivityThread 的内部类 ApplicationThread 会调用 scheduleCreateService 方法来启动 Service,在这个方法中会使用sendMessage方法向 H 类发送 CREATE_SERVICE 类型的消息,H类的 handleMessage 方法会对 CREATE_SERVICE 类型的消息进行处理,其中会调用 ActivityThread 的 handleCreateSerice方法
//frameworks/base/core/java/android/app/ActivityThread.java
private void handleCreateService(CreateServiceData data){
...
//通过 ContextImpl 的createAppContext 方法创建 ContextImpl
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//将该 ContextImpl 传入 service 的 attach 方法中
service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
}
/*Service.java*/
public final void attach(Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager){
//调用 ContextWrapper 的 attachBaseContext 方法
attachBaseContext(context);
}
//ContextWrapper.java
protected void attachBaseContext(Context base){
if(mBase != null){
throw new IllegalStateException("Base context already set");
}
//base指的是一路传递过来的 Activity 的 ContextImpl,将它赋值给 ContextWrapper的成员变量 mBase,当我们调用ContextWrapper中的方法时实际上就是调用的ContextImpl中的方法
mBase = base;
}
Service继承自ContextWrapper,同样可以使用Context方法