10.1.3 startActivity()的流程(1)
程序员可以直接调用startActivity()启动指定的Activity。前面说过,尽管从用户的角度来看,启动Activity有不同的方式,但是其主体流程是完全相同的,前端各种交互方式最后都会调用到startActivity()启动。因此,首先介绍startActivity()的流程。
1.概述
调用流程可大致归结为如图10-1和图10-2所示,由于版面限制,该图被划分为两部分。
![]() |
图10-1 startActivity()的内部调用流程 |
一般调用startActivity()方法是从用户单击桌面图标开始的,经过各种调用,最后导致调用startActivity()。本例假设当前正在运行A,而单击图标后会运行B。
AmS收到客户请求startActivity()后,会首先暂停当前的Activity,因此要判断mResumedActivity是否为空。在一般情况下,该值都不为空,如果不为空,AmS会通知A所在客户进程暂停,执行该Activty,并立即返回,返回后AmS就又"睡觉"去了。读者可能觉得奇怪,AmS"睡觉"去了,谁来启动B呢?这正是AmS的异步机制的好处,异步机制允许执行完一个命令后就去休息,而当远程执行完某个命令后再回调。这种方式广泛应用于Android的内核实际中,大家要迅速解除这种疑惑。
当A进程完成暂停后,报告AmS,这时AmS开始执行completePaused()。该方法中先要检查目标Activity是否在mHistory列表中,如果在,说明目标进程还在运行,目标Activity只是处于stop状态,还没有finish,所以通知B进程直接resume指定的Activity即可。如果不在mHistory列表中,则继续执行如图10-2所示的流程。
![]() |
图10-2 startActivity()的内部调用流程(续) |
检查目标Activity所在的进程是否存在,如果不存在则必须首先启动对应的进程。当对应的进程启动后,B进程会报告AmS自己已经启动,于是执行AmS的attachApplication()方法,该方法可理解为B进程请求AmS给自己安排(attach)一个具体要执行的Activity,此时AmS继续调用resumeTopActivity(),通知B进程执行指定的Activity。如果指定的HistoryRecord在B进程中不存在,则B调用handleLaunchActivity()创建一个该Activity实例;如果已经存在,则调用handleResumeActivity()恢复已有的Activity的运行。这个逻辑的意思就是说,在ActivityThread中可以存在同一个Activity的多个实例,对应了AmS中mHistory的多个HistoryRecord对象。在一般情况下,当调用startActivity(intent)的FLAG为NEW_TASK时,AmS会首先从mHistory中找到指定Activity所在的Task,然后启动Task中的最后面一个Activity;如果FLAG不为NEW_TASK,那么AmS会在当前Task中重新创建一个HistoryRecord,这就有可能创建同一个Activity的多个HistoryRecord对象,在ActivityThread端就可能创建同一个Activity类的多个实例。
2.单击图标的过程
关于startActivity()的细节过程如附图3所示,本图绘制时遵循以下规则:
假设class A的内部函数关系如下示意代码。
- public class Persedu {
- void f1(){
- f2();
- }
- void f2(){
- f3();
- }
- void f3(){
- x1();
- x2();
- x3();
- }
- void x1(){};
- void x2(){};
- void x3(){};
- }