这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
有关应用程序环境的全局信息的接口。 这是一个抽象类,其实现由Android系统提供。 它允许访问特定于应用程序的资源和类,以及调用应用程序级操作,例如启动活动、广播和接收意图等。
摘自官方文档(Context 的类注释也是这个) Context
Context 也就是上下文对象,是 Android 常用的类。我们常用的 Activity,Service 和 Application 都间接的继承了 Context。Context 是一个抽象类
// android.content.Context
public abstract class Context
日常开发中,使用 Context 的地方数不胜数,比如像弹 Toast、创建 Dialog、创建自定义 View 等等时候都需要传入 Context 对象,还有像启动 Activity、Service、访问资源和获取系统服务等等,都离不开 Context。所以 Android 同学必须掌握 Context 相关知识。
面试高频题:
- 应用中一共有几个 Context 对象
- Context、ContextImpl、ContextWrapper、ContextThemeWrapper 这几个类有什么关系?
- 说说 Application Context 的创建过程
应用中一共有几个 Context 对象
上面分析 Activity、Service 和 Application 都间接的继承了 Context。
空口无凭,凡事是要讲证据的。来来,我们这就来找找证据:
先来看看 Application
// 自定义的 Application
class MyApplication : Application() {}
// android.app.Application
public class Application extends ContextWrapper implements ComponentCallbacks2 {}
// android.content.ContextWrapper
public class ContextWrapper extends Context {}
Application 继承了 Context 的包装类 ContextWrapper。这是一个 Context 对象。
Activity
// android.app.Activity
public class Activity extends ContextThemeWrapper
// android.view.ContextThemeWrapper
public class ContextThemeWrapper extends ContextWrapper
// android.content.ContextWrapper
public class ContextWrapper extends Context {}
Activity 也继承了 Context 的包装类 ContextWrapper,所以每个 Activity 都是一个 Context 对象。
Service
// android.app.Service
public abstract class Service extends ContextWrapper
// android.content.ContextWrapper
public class ContextWrapper extends Context {}
Service 也继承了 Context 的包装类 ContextWrapper,所以每个 Service 都是一个 Context 对象。
- 应用中一共有几个 Context 对象 回答:Activity 和 Service 的数量总数 + 1, 1 是 Application 的数量。
Context、ContextImpl、ContextWrapper、ContextThemeWrapper 这几个类有什么关系?
根据第一题计算 Context 数量的分析,能看出来的,Activity、Service、Application 都间接继承自 Context
Activity -> ContextThemeWrapper -> ContextWrapper -> Context
Service -> ContextWrapper -> Context
Application -> ContextWrapper -> Context
从图中我们可以看出,ContextImpl 和 ContextWrapper 继承自 Context, ContextWrapper 内部包含 Context 类型的 mBase 对象, mBase 具体指向 ContextImpl, ContextImpl 提供了很多功能,但是外界需要使用并拓展 ContextImpl 的功能,因此设计上使用了装饰模式,ContextWrapper 是装饰类,它对 ContextImpl 进行包装,ContextWrapper 主要是起到了方法传递的作用, ContextWrapper 中几乎所有的方法都是调用 ContextImpl 的相应方法来实现的。 ContextThemeWrapper、Service 和 Application 都继承自 ContextWrapper, 这样它们都可以通过 mBase 来使用 Context 的方法,同时它们也是装饰类,在ContextWrapper 的基础上又添加了不同的功能。ContextThemeWrapper 中包含和主题相关的方法(比如 getTheme 方法),因此,需要主题的 Activity 继承 ContextThemeWrapper,而不需要主题的 Service 继承 ContextWrapper。
Context 的关联类采用了装饰模式,主要有以下的优点:
- 使用者(比如 Service )能够方便的使用 Context。
- 如果 ContextImpl 发生变化,它的装饰类 ContextWrapper 不需要做任何修改。
- ContextImpl 的实现不会暴露给使用者,使用者也不必关心 ContextImpl 的实现。
- 通过组合而非继承的方式,拓展 ContextImpl 的功能,在运行时选择不同的装饰类,实现不同的功能。 以上两段内容摘自皇叔的《Android 进阶解密》
Application Context 的创建过程
Application 的 Context 是在 Activity 创建过程中创建的 Activity 创建流程中会走到 ActivityThread 的 handleLaunchActivity
// ActivityThread#handleLaunchActivity
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
return a;
}
调用 Activity 启动过程中的核心实现 performLaunchActivity
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// app 的 Context 在这儿创建的
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// 通过反射方式创建 Activity 对象
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) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
...
// makeApplication 方法内部会判断 app 是否创建了 Application,若已创建则返回,若未创建则新建并返回
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
// attach 方法非常关键!!!内部创建了 PhoneWindow 对象
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,
r.assistToken);
...
// 这里开始 Attach 的生命周期 onCreate
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
获取 Application 对象, r.packageInfo
是 LoadedApk 类型的对象。所以需要卡 LoadedApk 的 makeApplication。
第 1 步:判断 mApplication 对象不为空 则直接返回已创建的 mApplication 对象。
第 2 步:获取 app 的 Application 的类名
第 3 步:如果没有设置过 Application 则会默认为 android.app.Application
第 4 步:通过 ContextImpl.createAppContext 创建 ContextImpl
第 5 步:通过 mInstrumentation.newApplication 创建 Application 对象
第 6 步:创建的 Application 对象赋值给 mApplication 缓存下来
第 7 步:调用 instrumentation 的 callApplicationOnCreate 来调用 Application 的 onCreate 方法
第 8 步:返回刚创建的 Application 对象
// android.app.LoadedApk#makeApplication
@UnsupportedAppUsage
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
// 1
if (mApplication != null) {
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
// 2
String appClass = mApplicationInfo.className;
// 3
if (forceDefaultAppClass || (appClass == null)) {
// 如果没有设置过 Application 则会默认为 android.app.Application
appClass = "android.app.Application";
}
try {
final 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);
}
// Rewrite the R 'constants' for all library apks.
SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
false, false);
for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) {
continue;
}
rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
}
// 4
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// The network security config needs to be aware of multiple
// applications in the same process to handle discrepancies
NetworkSecurityConfigProvider.handleNewApplication(appContext);
// 5
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
// 6
mApplication = app;
if (instrumentation != null) {
try {
// 7
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 8
return app;
}
先来看看 第 4 步:通过 ContextImpl.createAppContext 创建 ContextImpl 创建了 ContextImpl 对象并返回
// ContextImpl#createAppContext
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
0, null, opPackageName);
context.setResources(packageInfo.getResources());
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
return context;
}
第 5 步:通过 mInstrumentation.newApplication 创建 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;
}
通过 AppComponentFactory 来创建 Application 对象
// AppComponentFactory#instantiateApplication
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
@NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Application) cl.loadClass(className).newInstance();
}
最终是通过反射方式创建的 Application 对象。创建完 Application 对象后紧接着调用了 Application 对象 attach,传入了 LoadedApk#makeApplication 方法中第 4 步:通过 ContextImpl.createAppContext 创建的 ContextImpl 对象。
// Application#attach
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
调用了 attachBaseContext 将 ContextImpl 对象 context 传进去 attachBaseContext 是 Application 的父类 ContextWrapper 的方法
public class ContextWrapper extends Context {
Context mBase;
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
}
将 ContextImpl 类型对象 base 赋值给 mBase。
第 7 步:调用 instrumentation 的 callApplicationOnCreate 来调用 Application 的 onCreate 方法
// Instrumentation#callApplicationOnCreate
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
内部调用了 Application 对象的 onCreate 方法。
到此 Application 的创建流程已经梳理完了。相信我们通过 Applicaton 的创建过程会加深对 Context 的理解,包括 Context、ContextImpl 和 ContextWrapper。