进程、UI线程:
应用第一次启动时,会启动一个新的进程,该进程用应用的包名作为进程名(获取当前进程id的方法是:android.os.Process.myPid())。该进程会启动主线程ActivityThread,也叫UI线程,UI的绘制都应该在这个线程里完成。该进程里还有一些Binder服务线程,用于和系统进行通信。
Activity启动时ActivityManagerService会为其生成对应的ActivityRecord记录,并将其加入到回退栈(backstack)中,另外也会将ActivityRecord记录加入到某个Task中。ActivityRecord,backstack,Task都是ActivityManagerService的对象,由system_server进程负责维护,而不是由应用进程维护。
Task,backstack:
用户为了完成某个功能而执行的一系列操作会形成一个Activity序列,这个序列在Android应用程序中就称之为Task,它是从用户体验的角度出发,把一组组相关的Activity组织在一起而抽象出来的概念。在应用的Activity代码中,可以通过getTaskId()方法来获取当前Activity对象所在Task的Id。这些Activitys按照它们被打开的顺序,被安放在一个堆栈里(backstack)。在backstack中,属于同一个Task的ActivityRecord会放在一起,也会形成栈结构,也就是说后启动的Activity对象的ActivityRecord会放在Task的栈顶。
对于Task,我的理解是:Task是Task,进程是进程。进程为Task提供了其所需的Activity对象。例如:public class A extends Activity { ... }
如果Task1需要P进程的某个Activity类(例如上面的A)的对象,那么P就会new一个A的对象(假设叫obj1)给Task1使用;此时如果有另一个Task2也需要P进程的这个Activity类对象,那么P就会再new一个A的对象(假设叫obj2)给Task2使用。再推进一步,如果说此时obj2中调用了System.exit(0)方法,那么整个P进程就会被杀掉,obj1和obj2当然也不就复存在了。注意,此时Task还是存在的,假设现在Task1需要显示obj1这个Activity对象了,那么系统会重新创建P进程,重新new一个A的对象给Task1使用。
Activity的启动模式(launchMode):
Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。可以在AndroidManifest.xml中activity标签的属性android:launchMode中设置该Activity的加载模式。
standard模式:默认的模式,以这种模式加载时,每当启动一个新的活动,必定会构造一个新的Activity实例放到backstack(目标Task)的栈顶,不管这个Activity是否已经存在于backstack中;
注:遇到一个问题,当使用standard模式打开另一个应用的activity后,杀掉task根部的activity,会使整个task中的Activity对象全部被清除
singleTop模式:如果一个以singleTop模式启动的Activity的实例已经存在于backstack的栈顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中;如果以singleTop模式启动的Activity的一个实例已经存在于backstack中,但是不在栈顶,那么它的行为和standard模式相同,也会创建多个实例;
singleTask模式:这种模式下,每次启动一个Activity时,系统首先会在backstack中检查是否存在该活动的实例,如果存在,则直接使用该实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中(ps:不会调用onCreate方法了),并把这个活动之上的所有Activity统统清除(destroy);如果没有发现就会创建一个新的Activity实例;
几个关于singleTask模式的说明:
1,singleTask模式的Activity在整个backstack中只可以有一个ActivityRecord
2,只要两个Activity的taskAffinity属性一致,即使其中有一个Activity的启动模式为singleTask,它们对应的ActivityRecord会放在同一个task里,不管是从某个Activity跳转到singleTask类型的Activity,还是从singleTask类型的Activity跳转到其他Activity都是如此,除非跳转的其他Activity的启动模式是singleInstance。
3,假设Activity A的启动模式为singleTask,那么和A的ActivityReocord放在同一个task里的ActivityReocord所对应的Activity,必须与A的taskAffinity相同。也就是说,Activity A的ActivityReocord只会和同一应用的其它Activity的ActivityReocord放在同一个task里,并且这些同一应用的其它Activity不能设置特殊的taskAffinity。
singleInstance模式:总是在新的任务(task)中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其它Activity会自动运行于另一个Task中。当再次启动该Activity的实例时,会重新调用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例,(singleInstance即单实例)
关于taskAffinity:
在概念上,具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务(task)。
默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同应用中的activity的taskAffinity设置成相同的值。
为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task。
ps:singleTask模式演示:
假设Activity B的启动模式是singleTask,B所在的task里,B并没有处于栈顶,此时按HOME键,然后启动另一个应用的Activity X,则backstack的示意图是这样的:
这时,如果通过X启动B,则backstack的示意图是这样的:
跳转之后,B所在task中位于B之上的所有ActivityRecord都会被清除掉(C被清除了)
假设X是在C中启动出来的,backstack的示意图是这样的:
如果想要X与A、B、C在同一个task中,则需要确保它们的taskAffinity都是一样的,那样backstack的示意图是这样的:
这时,如果通过X启动B,则backstack的示意图是这样的:
ps:standard模式演示:
假设Activity B的启动模式是standard,B所在的task里,B并没有处于栈顶,此时按HOME键,然后启动另一个应用的Activity X,通过X再启动B,则backstack的示意图是这样的:
假设X是在C中启动出来的,则X与C在同一个task中,通过X再启动B,backstack的示意图是这样的:
ps:singleInstance模式演示:
假设Activity A,B,C属于同一应用,B的启动模式是singleInstance,其它为standard,Activity X属于另一应用。此时C调用起X,则backstack的示意图是这样的:
此时如果再从X调用起B,则backstack的示意图是这样的: