这篇博客是我通过google官网学习并结合自己的项目经验对Activity启动模式相关内容的总结。以下是google中文官网的学习地址,如果想了解更多细节可以到官网继续学习
google中文官网学习地址
在学习Activity启动模式之前我们需要先明白一个概念,任务和返回栈。
谷歌官方关于任务返回栈是这样描述的:
任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即返回栈)中。
我们的应用由多个Activity组成,每个 Activity 均应围绕用户可以执行的特定操作设计,并且能够启动其他 Activity,包括应用内以及其他应用的Activity,界面之间的跳转相当于是Activity之间的切换过程。为了保证这个过程的有序,不影响用户的体验,这些有关联的Activity会被放在一个任务里面,他们之间的切换过程会在一个堆栈里面按照先进后出的顺序进行排放,并保证这个顺序不会被改变。
设备主屏幕是大多数任务的起点。当用户在桌面触摸应用的图标时,该应用的任务将出现在前台。如果应用不存在任务,则会创建一个新任务,从该应用打开的所有Activity默认都会放在这个任务里面。
理解了任务和返回栈的概念,现在开始讲Activity的启动模式。
Activity的启动模式一共有四种:standard,singleTop,singleTask,singleInstance,他们的不同主要体现在应用内切换Activity和应用间切换Activity时表现出来的一些差异。
standard
以standard启动的Activity,每次启动都会创建新的实例,并且创建的Activity可以依附于多个任务里面。
举个例子:
假如我有个应用A,目前的任务栈自底向上是a->b->c,如果此时我再创建一个c,则任务栈变成a->b->c->c,这时候会发现任务栈里面存在两个c,按返回键时会重新回到c界面。你如果创建a或b结果也是会新建一个Activity实例置于栈顶,返回时就会出现相同的界面出现多次的情况。
那如果我是在其他应用以standard开启另一个应用的Activity会怎样呢?
这个要分两种情况:
1.假如此时应用A的任务栈是a->b->c,应用B未被开启过,也就是应用B的任务不存在,那么我从应用A以standard开启应用B的某个Activity d,这时应用A的任务栈就变成a->b->c->d,应用B仍然不存在任务。也就是说,我从A以standard开启不存在任务的应用B的某个Activity时,应用B的Activity会被添加到应用A的任务中,而不会为应用B新建一个任务。
2.如果在1的情况中应用B也存在任务栈,假如是d->e->f,那么从应用A开启应用B的d界面后,应用A的任务栈就变成a->b->c->d,应用B的任务还是d->e->f,这时候你就会发现d依附于两个不同的任务中,这也是以standard模式开启的特点,Activity可以存在于不同的任务中。
singleTop
以singleTop启动的Activity如果此时正处于当前任务的栈顶,则不会再新建Activity,而是直接取出栈顶的Activity显示。这里需要特别注意的是只有在当前任务的栈顶才不会重新创建,那如果是其他应用以singleTop开启另一个应用的某个Activity,此时该Activity已经存在于原本应用的栈顶,这时还是会新建一个Activity的实例并置于开启它的应用所在任务的栈顶。
还是举例子说明吧
第一种情况:应用内切换
假如应用A此时的任务栈自底向上依次为:a->b->c,则如果以singleTop开启c,此时任务栈仍然为a->b->c,那如果是开启b,则此时任务栈为a->b->c->b,因为b此时不在当前任务栈的栈顶,所以会重新创建一个实例并置于栈顶。
第二种情况:应用间切换
假如应用A此时的任务栈自底向上依次为:a->b->c,应用B此时的任务栈自底向上依次为:d->e->f,现在应用A以singleTop开启f,则应用A任务栈变为a->b->c->f,应用B的任务栈仍是d->e->f,虽然f已经存在于任务B的栈顶,但是因为任务A跟任务B不是同一个任务,所以在任务B启动f后还是会在任务B新建f的实例,并置于任务B的栈顶,如果此时任务B再开启f,则就不会再创建新的实例了。你会发现f存在于两个不同的任务里,所以以standard和singleTop开启的Activity都可以存在于不同任务栈中。
singleTask
根据安卓官方文档的说明,以singleTask开启的Activity系统会创建新任务并实例化位于新任务底部的Activity。但是我们会发现好像不是这样的,因为我们应用内声明为singleTask的Activity都是存在于同一个任务里面的。
这是因为以singleTask启动的Activity是否会开启新的任务,需要看taskAffinity的值是多少。在默认情况下,同一个应用程序中的所有Activity都具有相同的taskAffinity,就是我们应用的包名。taskAffinity相同的值会存在于同一个任务里,所以我们以singleTask开启的Activity都会默认添加到应用的当前任务中。
如果我们要让新开启的Activity存在新的任务里面可以通过设置taskAffinity来实现。taskAffinity值是一个字符串,可以设置为任意值,在清单文件设置。但是需要注意两点,第一,如果你设的taskAffinity值是应用包名则不会起作用,因为应用内所有Activity的taskAffinity默认是应用包名,第二,如果你设的taskAffinity值不是应用包名则需要以”.”开头,如果是应用包名以“.”开头也可以。
理解了taskAffinity的意思,我们现在来探讨以singleTask开启的Activity在切换过程中会呈现什么样的规律。
1.在同一个任务中只能存在一个Activity实例,而且只能存在于一个任务栈中不会同时依附于多个任务栈里,这点跟standard和singleTop是不一样的。
2.如果某个Activity已经存在于任务栈里面,重新切换到该Activity时会把位于它上面的所有Activity销毁掉,把该Activity置于栈顶。
我还是以应用内切换和应用间切换分别举例子:
应用内切换
假如应用A任务栈自底向上为a->b->c,现在启动b,这时候应用A的任务栈变成了a->b,会发现c已经被移出了任务栈,b重新回到了栈顶。那如果是开启d,假如d的taskAffinity是默认值,那么任务栈会变成a->b->c->d,如果taskAffinity的值被重新设置了,那么就会为d新建一个任务,并把d置于栈底,此时任务栈A仍是a->b->c,而d会存在于一个新的任务里。
应用间切换
假如应用A任务栈自底向上为a->b->c,应用B三个Activity d,e,f都是singleTask模式,应用B任务栈自底向上为d->e,此时应用A开启f,则会把应用B从后台拉到前台,此时A任务栈仍为a->b->c,应用B任务栈为d->e->f,这时点击返回会跳到e。
注意这里不会跳到应用A的栈顶Activity,这时候退栈顺序为f->e->d->c->b->a,也就是退栈时需要把应用B的所有Activity都退掉后才会跳到原本的应用A。那假如f的taskAffinity设置为不同的值,应用A开启f则会新建一个任务,这个任务只有f,并且将该任务拉到前台,此时应用A和应用B的任务栈都保持不变,按返回键时会退回到应用A的栈顶。
假如应用A任务栈自底向上为a->b->c,应用B三个Activity d,e,f都是singleTask模式,应用B任务栈自底向上为d->e->f,此时应用A开启f,则会把应用B从后台拉到前台。此时A任务栈仍为a->b->c,应用B任务栈为d->e->f,这时点击返回会跳到e。注意这里不会跳到应用A的栈定Activity,这时候退栈顺序为f->e->d->c->b->a,也就是退栈时需要把应用B的所有Activity都退掉后才会跳到原本的应用A。
SingleInstance
这种启动模式和singleTask有点相似,只不过系统不会向声明成singleInstance的Activity所在的任务当中再添加其它Activity。也就是说,这种Activity所在的任务中始终只会有一个Activity,通过这个Activity再打开的其它Activity也会被放入到别的任务当中。