1.四种启动模式:
“standard” (默认)
“singleTop”
“singleTask”
“singleInstance”
注意:如果不设置启动模式,默认是“standard”,
如果不指定affinity标记,默认是包名。
2.“standard” (默认)
Activity默认模式,所有的Activity遵循元素进栈出栈的特性,例如进栈序列为A->B->C->D,D呈现在页面上,按返回键出栈顺序久违D->C->B->A。
这种模式下,启动带有affinity标记的activity,首先判断task列表中有没有这个affinity;并且设置flag为NEW_TASK时,才会创建一个新的任务栈,把新activity放进去;当再次执行上面步骤时,是不会创建新实例的;
记住affinity和flag要同时使用才会起作用;否则还是会在原来的任务栈中创建新的实例;
3.“singleTop”
栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。避免栈顶的activity被重复的创建。
(1)要跳转的activity在栈顶:
可以看到,当是singleTop启动模式时,再次跳转到当前页面时,会调用onPause--->onNewIntent--->onResume。不会走oncreate,也就是直接复用了栈顶的activity。
(2)如果要跳转的activity不在栈顶会如何呢:
可以看到,当从SecondActivity再次跳转到MainActivity时,因为栈顶已经不是MainActivity了,所以又调用了MainActivity的onCreate方法,从新创建了一个新的activity。
(3)栈顶复用模式,应用场景:
IM,消息推送等页面,当消息频繁到来时,假如最上层可见的就是会话界面。完全可以复用这个activity界面。只做数据刷新即可。
登陆,假如网络或其他原因造成延迟,点击了两次登陆。就会生成两个主页。使用这种启动模式就可避免。
耗时操作返回页面, 从activity A启动了个service进行耗时操作,或者某种监听,这个时候你home键了,service收集到信息,要返回activityA了,就用singleTop启动,实际不会创建新的activityA,只是resume了。不过使用standard又会创造2个A的实例。
4.“singleTask”
(1)当栈顶不是要跳转的activity:
可以看到,跳回mainactivity时,secondactivity执行了onPause、onStop、onDestroy。mainactivity执行了onNewIntent、onRestart、onStart、onResume。所以它是复用了不在栈顶的mainactivity,把栈顶的secondActivity销毁了。
(2)栈顶是要跳转的activity:
可以看到,再次跳转到当前页面时,会调用onPause--->onNewIntent--->onResume。不会走oncreate,也就是直接复用了栈顶的activity。和singleTop模式的情况完全一致。
singleTask就相当于singleTop的加强版,不管怎样,只要栈中有这个activity,就一定会复用。至于它上面的那些,全部都会被销毁调。然后把复用的那个变成栈顶。
(3)taskAffinity:
前提是Activity的launchMode为singleTask或者设置了FLAG_ACTIVITY_NEW_TASK
taskAffinity是用来指示Activity属于哪一个Task栈的。
默认情况下,在一个app中的所有Activity都有一样的taskAffinity,一般是以包名为任务栈的名字。但是我们可以设置不同的taskAffinity,为这些Activity分Task。甚至可以在不同的app之中,设置相同的taskAffinity,以达到不同app的activity公用同一个Task的目的。
Note:
- Task的所有Activity只有一个taskAffinity
- Task的taskAffinity,是由Task的root activity定义
通常来说,如果Activity中设置launchMode的属性为SingleTask,当我们启动该Activity时,Android系统首先会检查在Task中,是否存在这个Activity的实例对象
存在:Android系统会直接把Intent路由到那个Task中存在的Activity实例对象上,会通过调用onNewIntent()方法处理,而非创建一个新的Activity实例对象。并且会把在它之上的其它Activity清理掉。
不存在:创建一个Activity实例对象这是肯定的,但是这里有个容易被忽视的盲点——Android系统首先会检查被调用的Activity的taskAffinity与调用方Task的taskAffinity是否一致。如果一致,则新创建的Activity实例对象将会被放在原来的Task之上。否则的话,系统会新建一个Task,然后把新创建的Activity实例对象作为一个根元素放在新Task之上。
可以看到,我在两个activity之间来回跳转的时候,并没有任何一个activity被销毁掉。也就是说,他们存在与不同的任务栈中。taskAffinity起到了作用。
(4)应用场景:
做浏览器、微博之类的应用,比如其他App需要打开我们的浏览器页面,就可以配置他为singleTask模式,保证他只有一个唯一实例,节约内存同时按下返回键后的感官也更顺畅。但是需要注意,提供给人调用的页面最好是栈底元素。因为,如果自己的客户端处于运行状态,按下Home键后台挂起。此时如果使用如果其他应用(比如说QQ)调起自己的客户端(浏览器)某个页面,不做任何处理的情况下,按下回退或者当前 Activity.finish(),页面都会停留在自己的客户端(因为自己的Application回 退栈不为空),这明显不符合逻辑的。
5.“singleInstance”
单一实例模式,整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。应用场景:呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。
可以得出以下结论:
1. 以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例。
2. 以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
3. 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中。
4. 被singleInstance模式的Activity开启的其他activity,能够在新的任务中启动,但不一定开启新的任务,也可能在已有的一个任务中开启。
非常感谢:
https://www.jianshu.com/p/0b908b0624e4
https://blog.youkuaiyun.com/zivensonice/article/details/51569502
下面是比较好的一个总结:
对于应用开发人员而言,中的launchMode属性,是需要经常打交道的。它有四种模式:”standard”, “singleTop”, “singleTask”, “singleInstance”。
standard模式, 是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。
而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视…)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验…),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。
singleTop模式,虽然破坏了原有栈的逻辑(复用了栈顶,而没有构造新元素进栈…),但并未开辟专属的Task。而singleTask,和singleInstance,则都采取的另辟Task的蹊径。标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。在Android源码提供的应用中,该模式被广泛的采用,最典型的例子,还是浏览器应用的主Activity(名为Browser…),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。
相比之下,singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行。这使得singleInstance的Activity,像一座孤岛,彻底的黑盒,它不关注请求来自何方,也不计较后续由谁执行。在Android默认的各个应用中,很少有这样的Activity,在我个人的工程实践中,曾尝试在有道词典的快速取词Activity中采用过,是因为我觉得快速取词入口足够方便(从notification中点选进入),并且会在各个场合使用,应该做得完全独立。
除了launchMode可以用来调配Task,的另一属性taskAffinity,也是常常被使用。taskAffinity,是一种物以类聚的思想,它倾向于将taskAffinity属性相同的Activity,扔进同一个Task中。不过,它的约束力,较之launchMode而言,弱了许多。只有当中的allowTaskReparen ting设置为true,抑或是调用方将Intent的flag添加FLAG_ACTIVITY_NEW_TASK属性时才会生效。如果有机会用到Android的Notification机制就能够知道,每一个由notification进行触发的Activity,都必须是一个设成FLAG_ACTIVITY_NEW_TASK的Intent来调用。这时候,开发者很可能需要妥善配置taskAffinity属性,使得调用起来的Activity,能够找到组织,在同一taskAffinity的Task中进行运行。
原文:https://blog.youkuaiyun.com/iromkoear/article/details/70187913