-
- 一 context与applicationactivityservice的继承关系
- 二 context与三者的对应关系描述
- 1 Application与Context的关系
- 2 Activity与Context的关系
- 3 Service与Context的关系
- 总结
一 、context与application、activity、service的继承关系
在开发过程中,经常会遇到使用context的情况,如通过context得到resource,通过context实现layoutInflater等,在代码环境中使用context,可用通过activity、application以及service来实现,那么这是为什么呢?因为三者都是继承自context抽象类的,如下图所示:
文章图片
可以看到,activity是继承自ContextThemeWrapper,而Service和Application继承自ContextWrapper对于ContextWrapper和ContextThemeWrapper而言,两者存在继承关系,最终继承自Context,而Context实际上是一个抽象类,它的实现是交给ContextImpl类负责,所以可以先提一下,app在启动时,application、activity和service三者能够关联到context,实际上都是在创建者三个要素的时候,同时实现了ContextImpl对象,具体证明放在之后描述。知道了activity、service和application与context的关系之后,也就理解了为什么可以把这仨当context来用了,其实context意义为场景,而activity、service及application从语义上理解也是场景的概念。
那么还有一个问题,activity等着仨是如何实现各自context的对应关系呢,需要分析app的启动过程了。
二、 context与三者的对应关系描述
在app启动时,或者启动一个新的activity及service中,实际上先由AmS(Activity Manager Service)来负责,AmS在一个进程中,启动的Activity或app是由另一个所在进程ActivityThread来实现,AmS负责管理ActivityThread中的相关具体过程,因此需要实现跨进程间的数据交互,而AmS和ActivityThread的数据交互入口是ActivityThread中的ApplicationThread,ApplicationThread是一个Binder变量,可以接受AmS传递来的数据。
2.1 Application与Context的关系
application初启动时,对于ActivityThread中,首先会执行到bindApplication方法,该方法的声明如下:
public final void bindApplication(String processName, ApplicationInfo appInfo, List providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services, Bundle coreSettings )
{
//这里是代码逻辑
}
可以在参数列表中发现有一个ApplicationInfo类型的参数appInfo,该数据实际上是由AmS传递过来的,且ApplicationInfo类型实现了Parcelable接口。在调用了bindApplication方法之后,通过传递来的appInfo,会构建一个AppBindData类型的数据,该数据构建完成之后,会由ActivityThread的内部Handler发送一个消息:
sendMessage(H.BIND_APPLICATION, data);
此时,ActivityThread由于实现了Handler的handleMessage,所以在收到消息为BIND_APPLICATION时会回调handleBindApplication方法,在该方法中可以找到创建Application的过程:
private void handleBindApplication(AppBindData data){
//...省略
Application app = data.info.makeApplication(data, restrictedBackupMode, null);
mInitialApplication = app;
//...省略
}
可以看到一个关键方法data.info.makeApplication()
这里的data就是之前创建完成的AppBindData类型的,也是handleBindApplication的传入参数;
info是LoadApk类型,在老版本中info实际上就是PackageInfo这个类,所以LoadApk就是PackageInfo,LoadApk这个类中有makeApplication方法,在该方法中存在实现context和application关联的步骤,查看makeApplication方法:
public Application makeApplication(){
//省略
ContextImp appContext=ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
//省略
}
在makeApplication方法中,创建了ContextImpl对象,并在ActivityThread中,通过Instrumentation对象创建了app,然后将app设置为context的外在体现,即setOuterContext方法,该方法如下:
final void setOuterContext(Context context){
mOuterContext = context;
}
该方法接收一个context对象,把其设置成mOuterContext,其实就是代言人的概念了。
以上就实现了application的创建过程中实现context关联的过程,再由流程图的形式描述一下:
文章图片
2.2 Activity与Context的关系
activity与context的关系也类似与application的流程,启动activity时,首先也是交由AmS进行处理,AmS会传递一个ActivityInfo类型的数据给ActivityThread,然后ActivityThread拿到了该数据之后执行后续的一系列操作。ActivityInfo也是一个实现Parcelable接口的类型。
ActivityThread接收到创建Activity的命令之后,会首先触发scheduleLaunchActivity方法:
public final void scheduleLaunchActivity(Intent intent, IBinder
token, int ident, ActivityInfo info,
compatInfo, String referrer, IVoiceInteractor
PersistableBundle persistentState,
List pendingNewIntents,
ProfilerInfo profilerInfo) {updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
ScheduleLaunchActivity这个方法相当于在接收到AmS传递来的ActivityInfo之后,执行的预处理工作,这个预处理主要是updateProcessState和构建ActivityClientRecord对象,完成之后sendMessage
在handleMessage方法中回调了handleLaunchActivity方法,在该方法中,通过Intent和ActivityClientRecord创建了Activity:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent){
//省略
Activity a = performLaunchActvity(r,customIntent);
//省略
}
看到了Activity是如何明面上创建的了,接下来执行到performLaunchActivity方法中:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
//省略
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.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);
}
}
//...
Context appContext = createBaseContextForActivity(r, activity);
//省略
}
从上面的代码中就了解了Activity对象是如何创建的,以及Context对象是如何关联到activity的,可以看看createBaseContextForActivity这个方法的具体实现:
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity){
ContextImpl appContext =ContextImpl.createActivityContext(this, r.packageInfo, r.token);
appContext.setOuterContext(activity);
Context baseContext = appContext;
//省略
}
可以看到在该方法中,同样通过ContextImpl的静态方法createActivityContext来创建ContextImpl对象,然后通过setOuterContext来设置activity为context的外部代言人
整体流程如下:
文章图片
2.3 Service与Context的关系
与上述两种情况类似,启动Service(注意这里是startService而不是bindService)时,首先AmS进行处理,包装出一个ServiceInfo类型的数据,ActivityThread接收到数据后首先执行scheduleCreateService方法:
public final void scheduleCreateService(IBinder token, ServiceInfo info, CompatibilityInfo compatInfo, int processState){
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
创建了CreateServiceData之后发送消息CREATE_SERVICE,然后得到handleMessage的响应,进入到handleCreateService方法中:
private void handleCreateService(CreateServiceData data){
//省略
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
//省略
}
在该方法中,首先通过getPackageInfoNoCheck得到了packageInfo对象,根据该对象得到ClassLoader后通过反射构建了service,获取了service对象之后,利用ContextImpl的静态方法得到了context,context设置了service为其外部代言人,之后创建了application,将service attach上去,最后启动onCreate方法。有一个疑问,为什么在创建了service的过程中需要构建application对象呢?可能是跟后台service依旧属于一个application,虽然没有前台界面的展示,没有明显的application构建,但是service需要依赖application,所以针对无界面、后台service启动的情况下需要创建application为service提供attach支持。
【Android|Application、Activity、Service和Context之间的构建关系】整体流程如下:
文章图片
总结
通过第二部分的分析,可以总结如下:不论是启动app还是某个activity,亦或是service,最初都需要提交给AmS,AmS相当于总负责人,总负责人处理好消息后打包成数据(ApplicationInfo、ActivityInfo及ServiceInfo),并将数据通过跨进程传递的方式递交给ActivityThread进行处理,ActivityThread在接收时对外首先暴露ApplicationThread这个Binder接口,然后获取到相应的数据之后执行创建application、activity及service的流程;同时在创建这仨时,通过ContextImpl的静态方法来创建ContextImpl对象,对象创建完成之后通过setOuterContext方法指定各类的外部代言人,但是该方法的参数是Context,而恰好Application、Activity及Service都继承自Context,所有可以有效充当contextImpl的外部代言人,来调用contextImpl中的方法,这就是application、activity及service是context的本质,本质在于以代言人的身份调用方法(好像属于一类设计模式?)。多提一句,contextImpl内的核心实现其实大部分都在LoadApk方法内具体完成的。