Android启动模式详解
standard
默认模式。在该模式下,Activity
可以拥有多个实例,并且这些实例既可以位于同一个task
,也可以位于不同的task
。每次都会新创建。singleTop
该模式下,在同一个task
中,如果存在该Activity
的实例,并且该Activity
实例位于栈顶则不会创建该Activity
的示例,而仅仅只是调用Activity
的onNewIntent()
。否则的话,则新建该Activity
的实例,并将其置于栈顶。singleTask
顾名思义,只容许有一个包含该Activity
实例的task
存在! 在android
浏览器browser
中,BrowserActivity
的launcherMode="singleTask"
,因为browser
不断地启动自己,所以要求这个栈中保持只能有一个自己的实例,browser
上网的时候, 遇到播放视频的链接,就会通过隐式intent
方式跳转找Gallery3D
中的MovieView
这个类来播放视频,这时候如果你点击home
键,再点击browser
,你会发现MovieView
这个类已经销毁不存在了, 而不会像保存这个MovieView
的类对象,给客户带来的用户体验特别的不好。就像别人总结的singleTask
模式的Activity
不管是位于栈顶还是栈底,再次运行这个Activity
时,都会destory
掉它上面的Activity
来保证整个栈中只有一个自己。
下面是官方文档中的介绍:
The system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method, rather than creating a new instance. Only one instance of the activity can exist at a time.
以singleTask
方式启动的Activity
,全局只有唯一个实例存在,因此,当我们第一次启动这个Activity
时,系统便会创建一个新的任务栈,并且初始化一个Activity
实例,放在新任务栈的底部,如果下次再启动这个Activity
时, 系统发现已经存在这样的Activity
实例,就会调用这个Activity
实例的onNewIntent
方法,从而把它激活起来。从这句话就可以推断出,以singleTask
方式启动的Activity
总是属于一个任务栈的根Activity
。 下面我们看一下示例图:
坑爹啊!有木有!前面刚说singleTask
会在新的任务中运行,并且位于任务堆栈的底部,这里在Task B
中,一个赤裸裸的带着singleTask
标签的箭头无情地指向Task B
堆栈顶端的Activity Y
,什么鬼?
这其实是和taskAffinity
有关,在将要启动时,系统会根据要启动的Activity
的taskAffinity
属性值在系统中查找这样的一个Task
:Task
的affinity
属性值与即将要启动的Activity
的taskAffinity
属性值一致。如果存在, 就返回这个Task
堆栈顶端的Activity
回去,不重新创建任务栈了,再去启动另外一个singletask
的activity
时就会在跟它有相同taskAffinity
的任务中启动,并且位于这个任务的堆栈顶端,于是,前面那个图中, 就会出现一个带着singleTask
标签的箭头指向一个任务堆栈顶端的Activity Y
了。在上面的AndroidManifest.xml
文件中,没有配置MainActivity
和SubActivity
的taskAffinity
属性, 于是它们的taskAffinity
属性值就默认为父标签application
的taskAffinity
属性值,这里,标签application
的taskAffinity
也没有配置,于是它们就默认为包名。
总的来说:singleTask
的结论与android:taskAffinity
相关:- 设置了
singleTask
启动模式的Activity
,它在启动的时候,会先在系统中查找属性值affinity
等于它的属性值taskAffinity
的任务栈的存在;如果存在这样的任务栈,它就会在这个任务栈中启动,否则就会在新任务栈中启动。 因此,如果我们想要设置了singleTask
启动模式的Activity
在新的任务栈中启动,就要为它设置一个独立的taskAffinity
属性值。以A
启动B
来说当A
和B
的taskAffinity
相同时:第一次创建B
的实例时,并不会启动新的task
, 而是直接将B
添加到A
所在的task
;否则,将B
所在task
中位于B
之上的全部Activity
都删除,然后跳转到B
中。 - 如果设置了
singleTask
启动模式的Activity
不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity
实例,如果存在,就会把位于这个Activity
实例上面的Activity
全部结束掉, 即最终这个Activity实例会位于任务的堆栈顶端中。以A
启动B
来说,当A
和B
的taskAffinity
不同时:第一次创建B
的实例时,会启动新的task
,然后将B
添加到新建的task
中;否则,将B
所在task
中位于B
之上的全部Activity
都删除,然后跳转到B
中。
- 设置了
singleInstance
顾名思义,是单一实例的意思,即任意时刻只允许存在唯一的Activity
实例,而且该Activity
所在的task
不能容纳除该Activity
之外的其他Activity
实例!
它与singleTask
有相同之处,也有不同之处。
相同之处:任意时刻,最多只允许存在一个实例。
不同之处:
- `singleTask`受`android:taskAffinity`属性的影响,而`singleInstance`不受`android:taskAffinity`的影响。
- `singleTask`所在的`task`中能有其它的`Activity`,而`singleInstance`的`task`中不能有其他`Activity`。
- 当跳转到`singleTask`类型的`Activity`,并且该`Activity`实例已经存在时,会删除该`Activity`所在`task`中位于该`Activity`之上的全部`Activity`实例;而跳转到`singleInstance`类型的`Activity`,并且该`Activity`已经存在时,
不需要删除其他`Activity`,因为它所在的`task`只有该`Activity`唯一一个`Activity`实例。
假设我们的程序中有一个Activity是允许其他程序调用的,如果想实现其他程序和我们的程序可以共享这个Activity的实例,应该如何实现呢?使用前面3种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个Activity在不同的返回栈中入栈时必然创建了新的实例。而使用singleInstance模式就可以解决这个问题,在这种模式下,会有一个单独的返回栈来管理这个Activity,不管是哪个应用程序来访问这个Activity,都共用同一个返回栈,也就解决了共享Activity实例的问题。
假设现在有FirstActivity、SecondActivity、ThirdActivity三个Activity, SecondActivity的启动模式是SingleInstance。 现在FirstActivity 启动SecondActivity,SecondActivity再启动ThirdActivity。
然后我们按下Back键进行返回,你会发现ThirdActivity竟然直接返回到了FirstActivity,再按下Back键又会返回到SecondActivity,再按下Back键才会退出程序,这是为什么呢?其实原理很简单,由于FirstActivity和ThirdActivity是存放在同一个返回栈里的,当在ThirdActivity的界面按下Back键时,ThirdActivity会从返回栈中出栈,那么FirstActivity就成为了栈顶Activity显示在界面上,因此也就出现了从ThirdActivity直接返回到FirstActivity的情况。然后在FirstActivity界面再次按下Back键,这时当前的返回栈已经空了,于是就显示了另一个返回栈的栈顶Activity,即SecondActivity。最后再次按下Back键,这时所有返回栈都已经空了,也就自然退出了程序。
- 邮箱 :[email protected]
- Good Luck!