关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够。这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理。
1.ActivityStack
ActivityStack从名称来看是跟栈相关的类,其实它是一个管理类,用来管理系统所有Activity的各种状态。它由ActivityStackSupervisor来进行管理的,而ActivityStackSupervisor在AMS中的构造方法中被创建。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
1.1 ActivityStack的实例类型
ActivityStackSupervisor中有多种ActivityStack实例,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
mHomeStack用来存储Launcher App的Activity的堆栈,mFocusedStack表示当前正在接收输入或启动下一个Activity的堆栈。mLastFocusedStack表示此前接收输入的Activity的堆栈。通过ActivityStackSupervisor提供了获取上述ActivityStack的方法,比如要获取mFocusedStack,只需要调用ActivityStackSupervisor的getFocusedStack方法就可以了:
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
ActivityStack中通过枚举存储了Activity的所有的状态,如下所示。 frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
通过名称我们可以很轻易知道这些状态所代表的意义。应用ActivityState的场景会有很多,比如下面的代码:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
overridePendingTransition方法用于设置Activity的切换动画,注释1处可以看到只有ActivityState为RESUMED状态或者PAUSING状态时才会调用WMS类型的mWindowManager对象的overridePendingAppTransition方法来进行切换动画。
在ActivityStack中定义了一些特殊状态的Activity,如下所示。
这些特殊的状态都是ActivityRecord类型的,ActivityRecord用来记录一个Activity的所有信息。从栈的角度来说(Activity任务栈是一个假想的模型),一个或多个ActivityRecord会组成一个TaskRecord,TaskRecord用来记录Activity的栈,而ActivityStack包含了一个或多个TaskRecord。
ActivityStack中维护了很多ArrayList,这些ArrayList中的元素类型主要有ActivityRecord和TaskRecord,其中TaskRecord用来记录Activity的Task。
我们知道Activity是由任务栈来进行管理的,不过任务栈是一个假想的模型,并不真实的存在。栈管理就是建立在这个假想模型之上的,有了栈管理,我们可以对应用程序进行操作,应用可以复用自身应用中以及其他应用的Activity,节省了资源。比如我们使用一款社交应用,这个应用的联系人详情界面提供了联系人的邮箱,当我们点击邮箱时会跳到发送邮件的界面。
社交应用和系统Email中的Activity是处于不同应用程序进程的,而有了栈管理,就可以把发送邮件界面放到社交应用中详情界面所在栈的栈顶,来做到跨进程操作。 为了更灵活的进行栈管理,Android系统提供了很多配置,下面分别对它们进行介绍。
Launch Mode都不会陌生,用于设定Activity的启动方式,无论是哪种启动方式,所启动的Activity都会位于Activity栈的栈顶。有以下四种:
Intent中定义了很多了FLAG,其中有几个FLAG也可以设定Activity的启动方式,如果Launch Mode设定和FLAG设定的Activity的启动方式有冲突,则以FLAG设定的为准。
除了这三个FLAG,还有一些FLAG对我们分析栈管理有些帮助。
接下来通过系统源码来查看FLAG的应用,在Android深入四大组件(一)应用程序启动过程(后篇)中讲过,根Activity启动时会调用AMS的startActivity方法,经过层层调用会调用ActivityStarter的startActivityUnchecked方法,如下面的时序图所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
注释1处用于初始化启动Activity的各种配置,在初始化前会重置各种配置再进行配置,这些配置包括:ActivityRecord、Intent、TaskRecord和LaunchFlags(启动的FLAG)等等。注释2处的computeLaunchingTaskFlags方法用于计算出启动的FLAG,并将计算的值赋值给mLaunchFlags。在注释3处将mLaunchFlags设置给Intent,达到设定Activity的启动方式的目的。接着来查看computeLaunchingTaskFlags方法。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
计算启动的FLAG的逻辑比较复杂,这里只截取了一小部分,注释1处的TaskRecord类型的mInTask为null时,说明Activity要加入的栈不存在。因此,这一小段代码主要解决的问题就是Activity要加入的栈不存在时如何计算出启动的FLAG。注释2处,ActivityRecord类型的mSourceRecord用于描述“初始Activity”,什么是“初始Activity”呢?比如ActivityA启动了ActivityB,ActivityA就是初始Activity。同时满足注释2和注释3的条件则需要创建一个新栈。注释4处,如果“初始Activity”所在的栈只允许有一个Activity实例,则也需要创建一个新栈。注释5处,如果Launch Mode设置了singleTask或singleInstance,则也要创建一个新栈。
我们可以在AndroidManifest.xml设置android:taskAffinity,用来指定Activity希望归属的栈, 默认情况下,同一个应用程序的所有的Activity都有着相同的taskAffinity。 taskAffinity在下面两种情况时会产生效果。
接着通过系统源码来查看taskAffinity的应用。ActivityStackSupervisor的findTaskLocked方法用于找到Activity最匹配的栈,最终会调用ActivityStack的findTaskLocked方法。 frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
这个方法的逻辑比较复杂,这里截取了和taskAffinity相关的部分。注释1处遍历mTaskHistory列表,列表的元素为TaskRecord,用于存储没有被销毁的Task。注释2处得到某一个Task的信息。注释3处将Task的rootAffinity(初始的taskAffinity)和目标Activity的taskAffinity做对比,如果相同,则将FindTaskResult的matchedByRootAffinity 属性设置为true,说明找到了匹配的Task。