Activity 显示调用
Android 系统内部已经做了很多的封装,这使得启动一个 Activity 变得异常简单。在显示调用的情况下,只需要通过如下代码即可完成:
|
|
源码分析
我的源码是基于 Android 8.0 进行源码分析,那么我们就从 Activity 的 startActivity 方法开始分析,经过一系列的源码追踪会来到 startActivityForResult 方法,代码如下:
|
|
在上面的代码中,我们只需要关注 mParent == null 这部分逻辑即可。mParent 代表的是 ActivityGroup,ActivityGroup 最开始被用来在一个界面中嵌入多个子 Activity,但是其在 API 13 中已经被废弃了,系统推荐代用 fragment 来代替 ActivityGroup,Fragment(android.app.Fragment 在 Android P 版本中被废弃,v4包下的 Fragment 可以使用)在使用时会更加的灵活。
在上面的代码中需要注意 mMainThread.getApplicatioinThread() 这个参数,他的类型是 ApplicationThread,ApplicationThread 是ActivityThread 的一个内部类,通过后面的分析可以发现,ApplicationThread 和 ActivityThread 在 Activity 的启动过程中发挥着很重要的作用。接着看一下 Instrumentation 的方法,代码如下:
|
|
从上面的代码可以看出,启动 Activity 真正的实现由 ActivityManager.getService() 的 startActivity 方法来完成。ActivityManagerService(下面简称为 AMS)继承了 IActivityManager.Stub,而 IActivityManager 是一个继承了 IInterfece 接口的接口,用于在在 Binder 中传输,因此可以看出 IActivityManager.Stub 实际上是一个 Binder,所以 AMS 也是一个 Binder,它是 IActivityManager.Stub 的具体实现。可以发现,ActivityManager 中,AMS 采用单例模式对外提供 Binder 对象,Singleton 是一个单例的封装类,第一次调用它的 get 方法时它会通过 create 方法来初始化 Binder 对象(也就是 AMS),在后续的调用中则直接返回之前创建的对象,这个过程的源码如下:
|
|
从上面的分析可以知道,Activity 由 ActivityManager.getService() 来启动,而 ActivityManager.getService() 实际上是 AMS,因此 Activity 的启动过程就转移到了 AMS 中,那么继续分析这个过程,就需要查看 AMS 的 startActivity 方法即可。
在分析 AMS 的 startActivity 方法之前,我们先看一下 Instrumentation 的 execStartActivity 方法中的 checkStartActivityResult(result, intent),直观上看起来这个方法的作用像是在检查启动 Activity 的结果,它的具体实现如下:
|
|
从上面的代码可以看出,checkStartActivityResult 的作用就是检查启动 Activity 的结果。当无法正确地启动一个 Activity 时,这个方法会抛出异常信息,其中最熟悉不过的就是 “Unable to find explicit activity class; have you declared this activity in your AndroidManifest.xml?” 这个异常了,当待启动的 Activity 没有在 AndroidManifest 中注册时,就会抛出这个异常。
接着我们开始分析 AMS 的 startActivity 方法,代码如下:
|
|
可以看出,Activity 的启动过程有转移到了 ActivityStarter 的 startActivityMayWait 方法中了,在 startActivityMayWait 中又调用了startActivityLocked 方法:
|
|
在 startActivityLocked 中又调用了 startActivity 方法:
|
|
在 startActivity 中又调用了一个重载的方法,这一操作看似不起眼,但是需要注意的是 「true」这个参数,它的方法签名为「doResume」,这个参数后边会用到。
继续向下,重载的 startActivity 方法调用了 startActivityUnchecked 方法。至此,我们可以准确无误的追踪到 Activity 的启动过程,如何证明?以上方法上面都有注释,会一步一步引导你进入正确的方法中,比如最后 startActivityUnchecked 的方法上的注释是:「标记:这个方法应该只能从 startActivity 调用」。
下面我简化一下 startActivityUnchecked 的具体实现:
|
|
接下来要调用的就是 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法,那么启动过程就跳转到了 ActivityStackSupervisor。
但是有个问题,resumeFocusedStackTopActivityLocked 方法在一个判断语句里面,通过对 ActivityStarter 类的追踪可以很容易的发现,这个 mDoResume 的初始值是 false,而这个字段到底是什么意思呢,字段上面也没有相关的注释。后经全局查找,最终找到了这个 mDoResume 字段状态变更之处。这便是方法内部一开始调用的 setInitialState 方法。
setInitialState 方法内部基本都是赋值,我就不上代码了,其中一句是 mDoResume = doResume;
这个 doResume 便是上边我让大家注意的 startActivity 的 doResume 的参数,在调用重载方法时,直接传入了一个 true。因此在设置完初始化状态以后,resumeFocusedStackTopActivityLocked 方法可以被调用。
同时,源码当中也给出了 mDoResume 字段的解释:「如果此时调用者要求恢复状态为 false,我们在记录中标记这一点,为的是我们能调过试图寻找正在顶部执行的 Activity 这一功能」
那么继续追踪 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法。resumeFocusedStackTopActivityLocked 内部调用 resumeFocusedStackTopActivityLocked 方法,然后调用 ActivityStack 的 resumeTopActivityUncheckedLocked,至此启动过程来到了 ActivityStack 类中。
|
|
resumeTopActivityUncheckedLocked 内部调用 resumeTopActivityInnerLocked 方法,resumeTopActivityInnerLocked 内部调用了 ActivityStackSupervisor 的 startSpecificActivityLocked 方法,startSpecificActivityLocked 方法源码如下:
|
|
从上面代码可以看出,startSpecificActivityLocked 方法调用了 realStartActivityLocked 方法,为了更清晰地说明 Activity 的启动过程在各种累之间的传递,这里用流程图加以说明。
在 ActivityStackSupervisor 的 realStartActivityLocked 方法中有如下一段代码:
|
|
那么剩下的内容就和书上的内容完全一致,我再重复写一遍也没有意义,对于读者也是浪费时间的一种行为。剩下的内容在 「Android 开发艺术探索」中 P326 ~ P336中。
最后,祝各位读者阅读愉快。