理解任务和返回栈
当执行一个确定的工作的时候,一个任务是和用户交互的activity的集合。这些activity被排列在栈中(返回栈),每一个activity是被打开的。例如,一个email app有一个activity去显示消息列表,当点击一个新的消息时打开一个新的activity,新的activity被加入到返回栈中。如果用户按下返回键,新的activity会从栈中弹出。
当app运行在多窗口环境中,系统为每一个窗口单独管理任务,每一个窗口可能有多个任务,系统基于每一个窗口来管理任务或任务组。
设备主屏幕是大多数任务的起始地方,当用户触摸app启动程序中的图标(主屏幕上的快捷方式),app的任务会出现在前台。如果app的任务不存在(app没有被使用过),然后一个新的任务会被创造并且main activity打开作为栈的根activity。
当 当前activity打开一个新的activity,新的activity会被压入栈的顶部并获取焦点。前一个activity 保留在栈中,但是被stop。当一个activity被stop,系统保留用户接口的当前状态。当用户按下back键,当前activity被弹出栈顶(activity被毁灭),并且前一个activity被恢复(前一个activity的UI状态被恢复)。在栈中的activity从来不被从新排列,只能被压入或者弹出栈。
下图展示了进栈和出栈
如果用户继续按下back键,在栈中的activity被弹出并显示前一个activity,直到用户返回到HOME屏幕。当所有的activity从栈中移除,任务不再存在。
一个任务是一个有凝聚力的单元,当一个新的任务打开时,或者按下home键返回到主屏幕,任务被移到后台。任务在后台运行,所有的activity是stop状态,这个任务的返回栈是完好的,这个任务只是丢失掉聚焦点被另一个任务取代。在图片2中,当前的任务A有三个activity在栈中,两个在当前activity之下。当用户按下home键,从主界面开启一个新的app。当home屏幕显示的时候,任务A进入后台。当新的app启动,系统启动一个新的任务为app使用他自己的activity栈。在和app交互之后,用户返回home屏幕并且选择app打开任务A。现在,任务A返回到前台,在栈中的三个activity是完好无损的,在栈顶的activity被恢复。同样,也可以这样返回到任务B。
注意:可以同时在后台执行多个任务。但是,如果用户同时运行多个后台任务,系统可能会开始销毁后台活动以恢复内存,从而导致活动状态丢失
因为在返回栈中的activity是从来不被再次排列的,如果app允许用户去开启一个单独的activity从多个activity中,一个新的activity实例被创建并且被放在栈顶(而不是将任何以前的活动实例带到顶部)。因此,在app中的一个activity可能被创建多次(也可能从不同的任务中)。在图片3中展示了这种情况。
总结activity和任务的默认表现:
当activity A开启activity B,activity A是stop状态,但系统会保留他的状态。如果用户按下back键在activity B,activity A恢复保留的状态。
当用户按下home键离开一个任务,当前activity进入stop状态并且他的任务进入后台。系统保留在栈中的每一个activity的状态。如果用户之后恢复这个任务通过选择快捷图标开启这个任务,这个任务处于前台并且恢复在栈顶的activity的状态。
如果用户按下back键,当前activity从栈中弹出并且毁灭。在栈中的前一个activity被恢复。当activity被毁灭,系统不会保留这个activity的状态。
activities可能被实例化多次,甚至从另一些任务中。
导航设计:
关于app导航如何工作在安卓中,阅读
管理任务
安卓管理任务和返回栈正如上述所说-把所有activity按照顺序放入同一个任务和后进先出的栈-大多数工作都工作的十分好,你不必关心你的activity如何和task和返回栈交互。但是,你可能想要停止默认行为。大概你想要在你的app中的一个activity启动一个新的任务,当activitiy是被start的时候。或者当你启动activity的时候,你想要打开一个现存的实例(而不是创造一个新的实例在返回栈的栈顶)。或者当用户离开任务的时候,你只想要在返回栈中保留根activity。
你可以使用manifest中的<activity>中的属性和在intent中的flags传递到startActivity()中,去实现这些事情。
<activity>中的可用属性:
intent中的flag:
在下面的部分,将会介绍如何使用这些属性和flag,定义如何和任务和返回栈交互
单独讨论activity在最近屏幕是如何描述和管理的,可以看
一般不要修改默认行为,如果要修改,请做充分的测试确保可用性。
默认启动模式:
启动模式允许你定义一个activity的实例如何和当前任务联系交互。你可以使用两种方式定义不同的启动模式。
l 利用mainfest文件
当在manifest文件中声明一个activity,你可以指定activity如何和task交互。
l 利用intent的flag
当你调用startActivity()时,你可以include一个flag在intent中。
例如,如果activity A启动activity B,B可以在manifest中定义如何和当前task进行交互,activity A也可以请求activity B应该如何和当前任务交互。如果两个activity都定义了activity B如何和任务交互,然后activity A的请求(在inent中定义的)比activity B的请求(在manifest中定义)更优先。
利用manifest文件
当声明一个activity在manifest文件,你可以指定activity如何利用这些元素和任务交互。
launchMode属性指定了一个指令,activity如何被启动到任务中。
Standard(默认模式):
默认。系统在任务中创建一个新的activity实例,activity可以被实例化多次,每一个实例可能属于不同的任务,并且一个任务可能有多个实例。
SingleTop:如果activity在顶部,再次被调用不会被创建,其它情况创建一个新实例
如果activity的实例早已存在在当前任务的顶部,系统会通过调用他的onNewIntent()方法找到这个实例,而不是创造一个新的实例。Activity可以被实例化多次,每一个实例可能属于不同的任务,一个任务可能有多个实例(仅限于在栈顶的activity不是现存的activity,下面解释)
例如,假设一个任务返回栈由activity A,B,C,D组成,D在栈顶。一个intent寻找activity D。如果D使用默认standard启动模式,一个新的实例被启动,栈就变成了A-B-C-D-D。然而如果是singleTop模式,现存的D的实例接收intent通过onNewIntent(),因为D实例在栈顶,所以不会被从新创建。然而,如果intent的是B,一个新的实例会被加到栈顶,尽管他的启动模式是singleTop。
singleTask:
系统创建一个新的task并且实例化在task根部的task。如果activity的实例早已存在在单独的task中,系统会找到这个实例,不会创建一个新的实例。在一个时间只能有一个activity的实例存在。
SingleInstance:
和singleTask同样,只是系统不会启动其他的实例在task中。Activity总是单例的,task中的唯一成员。启动的活动在单独的task中打开。
举另一个例子,安卓浏览器声明:web 浏览器activity应该总是在他自己的任务中打开-在<activity>中 声明singleTask启动 模式。这意味着如果你的app发出一个intent打开浏览器,浏览器中 的activity是不会放在你的app中的。而是,要么一个 浏览器的新的task被启动,或者如果浏览器的task早已经在后台运行了,这个任务会进一步处理新的intent。
无论是否一个activity在一个新的task中启动还是在同一个任务中,back按钮总是把用户带到前一个activity。然而,如果你启动一个指定了singleTask启动模式的activity,然后如果这个activity的实例已经存在了在一个后台任务中,那么拥有这个实例的整个任务都会被带到前台。图片4展示了这种场景。
如果想了解更多,看一下activity元素的文档:
多谢大家支持。