做了一年多两年的Android研发,Activity一直在使用,而关于Activity任务栈类型,一直都属于知道,了解的状态,一直没有深入进去研究,所以在开发过程中,也是一直用着default的任务栈模式。趁着这次遇到一个bug,那就顺便把这个问题深究,剖析清楚。
在开发GO搜索的时候,遇到一个bug,主要场景是这样的:GO搜索功能是一个独立的Activity,进入这个Activity的入口有很多个,而且这些入口可能是在输入法键盘上,有的是在桌面的widget上,所以就遇到了这样一个问题,当你点击输入法主程序,按home键退出的时候,此时在输入法键盘或者从widget中进入GO搜索Activity时,Activity会被加载在了输入法主程序的任务栈中,此时退出GO搜索Activity时,系统会退回任务栈中的上一个任务,因此会造成一种用户没有进入输入法主程序,而主程序被调起来的错觉。
首先我们来分析一下上述问题的出现原因,看以下表:
从以上表就可以很清楚的看出,之所以会出现这么一个场景,其实就是,GOSearchActivity跟输入法主程序共用了一个任务栈所导致的,那么我们猜想,只要将他们放在不同的任务栈,那么,就应该不会出现了吧。
按照正常逻辑,接下来就到分析Android 任务栈的时候了,我们知道,Android Activity有四种任务类型,分别为Standard、SingleTop、SingleTask、SingleInstance。接下来我们根据Android API 文档一一来看一下:
Use Cases | Launch Mode | Multiple Instances? | Comments |
Normal launches for most activities | " | Yes | Default. The system always creates a new instance of the activity in thetarget task and routes the intent to it. |
" | Conditionally | If an instance of the activity already exists at the top of the target task,the system routes the intent to that instance through a call to its | |
Specialized launches (not recommended for general use) | " | No | The system creates the activity at the root of a new task and routes theintent to it. However, if an instance of the activity already exists, the systemroutes the intent to existing instance through a call to its |
" | No | Same as " |
通过以上Android 的解释,首先我们来看,Standard 和 SingleTop都是在调用者的栈中去创建实例,唯一不同的是,在singleTop的模式下,如果将要启动的Activity已经位于调用者的栈顶了,则不会再创建实例,只会调用其onNewIntent方法,不会出现多次返回同一个activity,再返回的时候要返回很多次的情况。因此在这两种模式下,就会导致我们之前遇到的问题。
接下来我们看一下singleTask和singleInstance两种启动模式,在singleTask模式下,系统会为该activity创建一个任务栈,并且只会有一个实例,并且以这个Activity为根的所有activity,都会在这个栈中进行。而singleInstance则跟singleTask相似,只不过会更加决绝一点,他完全是孤立在一个task栈中,这个task栈中只有他一个实例,由他创建的activity也会移到其他的任务栈中。
很显然,对于刚开始说的那个bug,只能在singleTask或者singleInstance中选择一种,因为GOSearchActivity完全是一个孤立的Activity,只会被其他Activity启动,没有启动其他Activity的作用,因此,选择singleInstance来解决该问题,若是考虑该activity可能会唤醒其他的activity的话,则用singleTask来解决也是就可以的。
还有一个必须在最后说一下,就是在后两种启动模式,在正常的情况下是不被推荐使用的,除非出现开始说的问题的特殊需要,因为创建一个task的性能和开销会比在原有的task进行穿件会高很多。会在一定程度影响打开的性能。所以,请慎用。