• 一 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抽象类的,如下图所示:

service的nodeport 外部怎么请求 service construction_ide

可以看到,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关联的过程,再由流程图的形式描述一下:

service的nodeport 外部怎么请求 service construction_ide_02

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的外部代言人

整体流程如下:

service的nodeport 外部怎么请求 service construction_数据_03

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支持。

整体流程如下:

service的nodeport 外部怎么请求 service construction_framework_04

总结

通过第二部分的分析,可以总结如下:

不论是启动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方法内具体完成的。