Android开发-Context理解(Applicatiion、Activity、Service 的Context区别)
程序员文章站
2022-03-29 08:12:36
...
Context理解
Activity、Service、Application类继承关系
借助Context真正的实现类ContextImpl理解上面关系
Context 类提供了一组通用的 API;
ContextImpl 实现了 Context 所有的功能,为 Activity等应用组件提供 Context 对象;
ContextWrapper 包含一个真正的 ContextImpl 的引用 mBase,然后就是ContextImpl 的装饰者模式
ContextThemeWrapper 内部包含了 Theme 相关的接口,即android:theme 指定的属性;
Context 的数量及作用域
Context 数量 = Activity 数量 + Service 数量 + 1(Application 数量)
Context作用域 | Application | Activity | Service |
---|---|---|---|
Start an Activity | 不推荐 | YES | 不推荐 |
Show a Dialog | NO | YES | NO |
Layout Inflation | 不推荐 | YES | 不推荐 |
Start a Service | YES | YES | YES |
Send a Broadcast | YES | YES | YES |
Register Broadcast | YES | YES | YES |
Load ResourceValues | YES | YES | YES |
极大多数的场景Context对于各个组件是通用的,但是:
- Dialog必须依附于Actiivity,否则会出错。
- 启动的Activity是基于栈的,但是非Activity是没有栈的概念,所以需要指定FLAG_ACTIVITY_NEW_TASK,此时候Activity 是以SingleTask启动的,不推荐使用
- Application 和 Service 中去 layout inflate 也是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。所以这种方式也不推荐使用
获取Context对象
- View 的 getContext 方法,返回 View 的 Context,通常是当前正在展示的 Activity 的对象,通常在自定义 View 时会用到;
- Activity.this 返回当前 Activity 实例,如果是 UI 控件需要使用 Activity 作为 Context 对象,但是默认的 Toast 实际上使用 ApplicationContext 也可以;
- Activity 和 Service 的getApplication 方法,返回 Application的实例,Application是个单例,返回的是单例对象;
- getApplicationContext 方法,获取当前应用的 Context 对象,也就是Application对应的Context,与上一个方法不同的是依附的对象不同;
各个组件实例化Context的过程
Context 的实现是 ContextImpl,Activity、Application 和 Service 的创建都是在 ActivityThread 中完成的,分析ActivityThread中,实例并联系ContextImpl的过程。(activity启动过程中会调用到performLaunchActivity方法,具体的activity的启动过程课参考Activity的启动过程)
Activity 中 ContextImpl实例过程
//创建Activity过程
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
****************
if (activity != null) {
//实例化ContextImpl过程
Context appContext = createBaseContextForActivity(r, activity);
*******************************************
//attach方法,将context和组件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);
********************************************
return activity;
}
//createActivityContext就是一个静态方法,创建一个ContextImpl
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
*************************
//创建ContextImpl
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
//核心方法:创建ContextImpl后,利用ContextImpl的setOuterContext(Context方法),
//将ContextImpl的成员mOuterContext复值为Activity这个Context.也就是让ContextImpl内部持有Activity
appContext.setOuterContext(activity);
//创建ContextImpl 直接赋值给你父类Context
Context baseContext = appContext;
*************
}
return baseContext;
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
*************************************
attachBaseContext(context);
************************************
mCurrentConfig = config;
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
//父类 ContextWrapper.java中的attachBaseContext方法
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
Servicie中 ContextImpl实例过程
和Activity中实例Context过程一样的
private void handleCreateService(CreateServiceData data) {
*************************************************
//创建ContextImpl
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//核心方法
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
//将Context绑定Service
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
***************************************************
}
上述创建Service过程中,ContextImpl.createAppContext 创建ContextImpl,然后绑定Context:service.attach
Application中 ContextImpl实例过程
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
****************************************************
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
********************************************************
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
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);
}
}
}
return app;
}