做了一年多两年的Android研发,Activity一直在使用,而关于Activity任务栈类型,一直都属于知道,了解的状态,一直没有深入进去研究,所以在开发过程中,也是一直用着default的任务栈模式。趁着这次遇到一个bug,那就顺便把这个问题深究,剖析清楚。

在开发GO搜索的时候,遇到一个bug,主要场景是这样的:GO搜索功能是一个独立的Activity,进入这个Activity的入口有很多个,而且这些入口可能是在输入法键盘上,有的是在桌面的widget上,所以就遇到了这样一个问题,当你点击输入法主程序,按home键退出的时候,此时在输入法键盘或者从widget中进入GO搜索Activity时,Activity会被加载在了输入法主程序的任务栈中,此时退出GO搜索Activity时,系统会退回任务栈中的上一个任务,因此会造成一种用户没有进入输入法主程序,而主程序被调起来的错觉。

首先我们来分析一下上述问题的出现原因,看以下表:

Android 手动清除任务堆栈 android task任务栈分配_Tasks

从以上表就可以很清楚的看出,之所以会出现这么一个场景,其实就是,GOSearchActivity跟输入法主程序共用了一个任务栈所导致的,那么我们猜想,只要将他们放在不同的任务栈,那么,就应该不会出现了吧。

按照正常逻辑,接下来就到分析Android 任务栈的时候了,我们知道,Android Activity有四种任务类型,分别为Standard、SingleTop、SingleTask、SingleInstance。接下来我们根据Android API 文档一一来看一下:

Use Cases

Launch Mode

Multiple Instances?

Comments

Normal launches for most activities

"standard"

Yes

Default. The system always creates a new instance of the activity in thetarget task and routes the intent to it.

"singleTop"

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 itsonNewIntent() method, rather than creating anew instance of the activity.

Specialized launches

(not recommended for general use)

"singleTask"

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 itsonNewIntent() method, rather than creating anew one.

"singleInstance"

No

Same as "singleTask", except that the system doesn't launch anyother activities into the task holding the instance. The activity is always thesingle and only member of its task.

通过以上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进行穿件会高很多。会在一定程度影响打开的性能。所以,请慎用。