Android开发-Context理解(Applicatiion、Activity、Service 的Context区别)
前言
以前书籍上面看过,分析过,同事问了一下,蒙了!现在总结一下,搞清楚Context是什么东东,四大组件中的区别又是怎样的。
Context 树装结构
理解:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
接口有关应用程序环境的全局信息。 这是一个抽象类,其实现由Android系统提供。 它允许访问特定于应用程序的资源和类,以及对诸如启动活动,广播和接收意图等应用程序级操作的上调。
有两个直接子类,以上间接子类外还有其它四十直接子类和间接子类。
Activity、Service、Application 对应的Context API理解
Context | 解释 |
---|---|
Activity | An activity is a single, focused thing that the user can do. |
Service | A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. |
Application | Base class for maintaining global application state. |
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 中 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);
*******************************************
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;
}
创建activity过程中,创建的appContext就是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;
}
createActivityContext就是一个静态方法,创建一个ContextImpl
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}
以上已经明确了创建ContextImpl流程了,那么是怎么和组件Activity联系起来的呢?
回到performLaunchActivity方法,在创建一个Activity的过程中,有一个attach方法
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);
具体代码如下:
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;
}
跟踪attachBaseContext(context)方法
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
api这么解释的:给Context的包装类一个Context,所有Context相关的请求将通过这个context来代理实现。
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;
}
总结:
这些是Context基本内容,必须掌握的。
- Context的实例ContextImpl,代理了Context的所有操作,Context只是一个抽象的类.
- 在ActivityThread.java中实例化三个Context相关的组件过程,以及和ContextImpl绑定过程。
-Context相关的作用域