![Android程序员面试笔试宝典](https://wfqqreader-1252317822.image.myqcloud.com/cover/682/39130682/b_39130682.jpg)
1.1.2 启动模式
启动模式的意思就是一个Activity是以怎样的一种启动方式来跳转到当前页。设置启动模式的方法也有两种。第一种用得比较多:在配置文件AndroidManifest.xml里用android:launchMode来指定,有四种模式可指定,分别是standard、singleTop、singleTask和singleInstance。这四种模式将在本节中逐一详细讲解;第二种设置方式则是通过在Intent中设置标记位来指定启动模式。
在讲解启动模式之前,还需要知道“任务栈”的概念。什么是任务栈?任务栈,即Task,它是一种用来保存和管理Activity的数据结构,也是所有Activity的集合。它遵循“后进先出”规则,假如当前页是ActivityA,点击按钮启动ActivityB,此时ActivityB就入栈,处于栈顶位置,而ActivityA则位于ActivityB之下,所以当前页就跳转为ActivityB了。这就是正常的启动模式,而往往实际开发中有时并不会只想要正常的启动模式,这时就需要用到上文提到的两种方式来指定其他启动模式了,尤其是第一种方式的四种模式是最常用的。
(1)standard
标准模式,如果不指定android:launchMode,默认就是standard模式。它就是常说的正常情况下的模式,每次启动一个活动时,就会创建一个实例,然后被启动的活动入栈,并处于栈顶的位置。
下面通过代码来实现standard模式,在MainActivity的onCreate()方法里用Intent来实现跳转,而这里决定让MainActivity要跳转的活动是自己,因为这样能更好地看出在standard模式下活动是怎样启动的:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/15_01.jpg?sign=1739911771-NMnX06T0fX71td5h7vT8MN8sWhr3KYRo-0-89e06ae4162bc9c44e1fd46421b9a514)
然后连续点击按钮3次,打印结果如下:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/15_02.jpg?sign=1739911771-j6sZBDWUG9DUgWtwY25r13UGlNR69HbS-0-0a224bd22260faa524590ee95e40fd1b)
从运行结果可以看出,MainActivity的确是被创建了3个实例,每启动一次,就创建一个新实例。
(2)singleTop
在该模式下启动Activity,系统会先检查任务栈栈顶是否有该Activity实例,如果有则直接使用它,调用onNewIntent()方法;如果没有则创建新的实例并且入栈到栈顶。设置该模式的方法就是在AndroidManifest.xml文件里用android:launchMode来指定:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/15_03.jpg?sign=1739911771-1FWGJhspflbEYs6WCyUNDnUnnC6sC3yw-0-80aaa21ea8cc6f11b52365bfe7dbd949)
MainActivity.java里的代码不变,运行程序,然后再次连续点击3次跳转按钮,打印结果如下:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/15_04.jpg?sign=1739911771-UnVGyCFY9mn3iWKqpasUwBRicrnc1dMo-0-6712b59c4134cfd5d3238d42d4e98fec)
从运行结果可以看出,不管按多少点跳转按钮,MainActivity只有一个实例,因为它在栈顶位置了,只需直接使用它就可以,不需要创建新的实例。
(3)singleTask
经过上文讲解,可以知道singleTop是栈顶复用活动实例:活动A设置了singleTop模式,当活动A启动活动B,然后活动B再启动回活动A时,因为此时处于栈顶位置的是活动B而不是活动A,所以还是会创建新的活动A实例,这是singleTop模式的效果。但是如果实际开发中有需求是要求整个应用就只存在活动A一个实例,不管怎么启动,都只使用这一个实例,那又该如何实现呢?所以此时就需要设置singleTask模式了:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/16_01.jpg?sign=1739911771-EnD464TCwL4d4w2hpaI0aHThW9qsorZQ-0-6eaf63756fbe9ef3beeb621bfc063410)
然后创建另一个活动类BActivity,用它来启动MainActivity:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/16_02.jpg?sign=1739911771-OTBC9zM9IwStCe5diVXiw8NGX3ZcsTpI-0-564b386d572793b480b69b2cbd007a7f)
最后MainActivity改为启动BActivity:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/16_03.jpg?sign=1739911771-htifjD8fQ8ASTDpEzTyJ6nthEFQlmyx6-0-c642f2536053cab872a63a0a65cd89c1)
运行程序后,先点击MainActivity的按钮启动BActivity,然后再点击BActivity的按钮启动MainActivity,打印的结果如下:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/16_04.jpg?sign=1739911771-49jq4PLP7LYfk1CmW4fRpOLk3mlPUaBJ-0-2c995d90fc3c5b3f0dee83796261b27a)
从运行结果可以看出,当在BActivity里点击按钮启动了MainActivity后,并没有创建新的MainActivity实例,这就是singleTask模式的作用了。
这里要再介绍一个知识点就是taskAffinity属性。该属性跟singleTask是密切相关的,因为其实该模式下启动活动时,最先开始还有一个任务栈匹配的过程,就是会先根据需要的任务栈里找活动实例,而这个需要的任务栈就是通过taskAffinity属性来指定的。当然也可以不指定,这样就默认为taskAffinity值为包名。
所以,最后来总结一下singleTask模式:如果是在同一个应用中(taskAffinity值一样)启动Activity时,系统先检测任务栈中是否存在该Activity,如果存在则直接使用该活动实例,让它置于栈顶,而它之上的其他活动纷纷出栈。如果不存在该实例,则创建该活动新的实例,置于栈顶。如果不是在同一应用中(taskAffinity值不一样),而是其他应用中来启动该模式下的Activity时,那么系统会创建一个新的任务栈,创建该活动新的一个实例,将它置于该新建任务栈栈顶。
(4)singleInstance
在该模式下启动Activity时,系统会先创建一个新的任务栈来专门存储与管理该Activity,而且该Activity具有全局唯一性,也就是该任务栈中只有这个Activity实例,任何应用只要启动该Activity,用的都是这一个实例。下面用代码实现该模式下的效果,先把MainActivity设置为singleInstance模式:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/17_01.jpg?sign=1739911771-NdzlMKvRHDWIrcKlokGgMbnmasv8Q9TO-0-4ab1a5ae7e9f1e8154c682a82953ab16)
然后把MainActivity的任务栈id打印出来:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/17_02.jpg?sign=1739911771-eOzeCrOa7LfuGR0vX41eH1NBPYVBGRGT-0-e796c6b5157b25bee6a12b450e519814)
接着也把BActivity的任务栈id打印出来,最后运行程序,在MainActivity页面里点击按钮跳转启动BActivity,然后在BActivity页面里点击按钮跳转启动MainActivity,打印的结果如下:
![](https://epubservercos.yuewen.com/FCD2F4/20516007501589706/epubprivate/OEBPS/Images/17_03.jpg?sign=1739911771-7za6KorEaVIYyUIW2yqaIPPg5aeelEMB-0-2e30433bdbe3b9f38329957d38bcabe2)
从运行结果可以看出,两个活动各自所处的任务栈是不一样的,而且最后MainActivity也只有一个实例,这就是singleInstance模式的作用了。