Application、Activity、Service和Context之间的构建关系

来源:互联网 发布:服务器端口怎么关闭 编辑:程序博客网 时间:2024/04/30 16:03

    • 一 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<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> 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<ReferrerIntent> 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支持。

整体流程如下:
这里写图片描述

总结

通过第二部分的分析,可以总结如下:不论是启动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方法内具体完成的。
0 0
原创粉丝点击