Application、Activity、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方法,该方法的声明如下:

可以在参数列表中发现有一个ApplicationInfo类型的参数appInfo,该数据实际上是由AmS传递过来的,且ApplicationInfo类型实现了Parcelable接口。

       在调用了bindApplication方法之后,通过传递来的appInfo,会构建一个AppBindData类型的数据,该数据构建完成之后,会由ActivityThread的内部Handler发送一个消息:

此时,ActivityThread由于实现了Handler的handleMessage,所以在收到消息为BIND_APPLICATION时会回调handleBindApplication方法,在该方法中可以找到创建Application的过程:
可以看到一个关键方法data.info.makeApplication()

        这里的data就是之前创建完成的AppBindData类型的,也是handleBindApplication的传入参数;info是LoadApk类型,在老版本中info实际上就是PackageInfo这个类,所以LoadApk就是PackageInfo,LoadApk这个类中有makeApplication方法,在该方法中存在实现context和application关联的步骤,查看makeApplication方法:

在makeApplication方法中,创建了ContextImpl对象,并在ActivityThread中,通过Instrumentation对象创建了app,然后将app设置为context的外在体现,即setOuterContext方法,该方法如下:
该方法接收一个context对象,把其设置成mOuterContext,其实就是代言人的概念了。

       以上就实现了application的创建过程中实现context关联的过程,再由流程图的形式描述一下:

2.2 Activity与Context的关系

        activity与context的关系也类似与application的流程,启动activity时,首先也是交由AmS进行处理,AmS会传递一个ActivityInfo类型的数据给ActivityThread,然后ActivityThread拿到了该数据之后执行后续的一系列操作。ActivityInfo也是一个实现Parcelable接口的类型。

ScheduleLaunchActivity这个方法相当于在接收到AmS传递来的ActivityInfo之后,执行的预处理工作,这个预处理主要是updateProcessState和构建ActivityClientRecord对象,完成之后sendMessage
看到了Activity是如何明面上创建的了,接下来执行到performLaunchActivity方法中:
从上面的代码中就了解了Activity对象是如何创建的,以及Context对象是如何关联到activity的,可以看看createBaseContextForActivity这个方法的具体实现:
可以看到在该方法中,同样通过ContextImpl的静态方法createActivityContext来创建ContextImpl对象,然后通过setOuterContext来设置activity为context的外部代言人

       整体流程如下:

2.3 Service与Context的关系

        与上述两种情况类似,启动Service(注意这里是startService而不是bindService)时,首先AmS进行处理,包装出一个ServiceInfo类型的数据,ActivityThread接收到数据后首先执行scheduleCreateService方法:

创建了CreateServiceData之后发送消息CREATE_SERVICE,然后得到handleMessage的响应,进入到handleCreateService方法中:

       在该方法中,首先通过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方法内具体完成的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容