Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack

Tasks and Back Stack

一个app一般包含多个activities,每个activity执行不同任务。

Task是与用户交互执行一系列任务的activities集合,这些activities已打开顺序排列在一个栈堆中。

用户点击主页面的图标或者快捷方式,如果此应用从未被执行过,那么会创建一个新的task,主界面activity作为这个task的根activity,当根activity启动其他界面,一个新的activity会被压到task的栈顶并获取焦点。此时根activity仍然在task中保存,当用户按返回键时,当前的activity会被弹出task栈堆并销毁,前一个activity重新resumes(之前UI上的状态数据重新加载)。

Task中的activities顺序永远不会重排,只有push(入栈)和pop(出栈)两种动作,作为栈堆,保持着后进先出的原则。

 

Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack

如图所示,1是task的根activity;1启动2之后,2入栈,1被压到栈底,2在栈顶;2启动3之后,3入栈;返回键,3出栈被销毁,2继续在栈顶。这个task中所有在栈顶的activity都是可见并获取用户焦点的界面。

当所有activities都出栈后,那么这个task也就不存在了。

 

Task可以作为一个整体单元,可以被整体移动到后台,当用户通过Home键返回主界面并启动新的task。

Note:多个task可以同时在后台,但是有可能被系统在回收内存时销毁。

 

如下是activities和tasks的默认行为:

  • A 启动 B,A被停止,系统保存A的状态数据。如果用户在B界面按返回键,B销毁,A恢复保存的状态数据。
  • 用户按Home键离开某个task,task中所有activities停止,并退到后台,如果用户而后通过桌面图标启动此task,此task会切到前台并恢复栈顶activity。
  • 如果用户按返回键,当前栈顶的activity会出栈,并被销毁,下一个切到栈顶的activity会恢复。activity被销毁后,系统不会保存其状态数据。
  • activities能够被实例化多次,即使在不同的tasks。

 

当系统由于内存回收销毁在后台的task中的activities时,这些activities界面用户临时数据会丢失(即便如此,task中的顺序依旧存在),当这些activities重新回到栈顶时,不是通过resume,而是通过recreate。为了避免此类数据丢失,强烈建议通过onSaveInstanceState()来保存临时数据。

管理Tasks

有时候你需要一个activity在每次启动时都是重新创建一个新的task,而不是安排到现有的task中;或者你创建activity时,直接使用现有已经创建的activity实例,而不是在栈顶创建新的实例;又或者你想用户离开task后清除根activity之外的其他activities。

你可以通过<activity>的属性和intent的flag来改变默认的行为。

<activity>属性如下:

intent的flag如下:

Caution:多数应用不需要改变系统的默认行为,如果你确定需要改变默认行为,那么你需要确保启动、返回等场景下应用的可用性,有可能返回键的行为会与用户的预期有冲突。

定义启动模式

启动模式允许你定制一个新的activity实例与当前task的关联,有如下两种方式:

  • 用manifest文件:被启动时此activity该如何关联
  • 用intent flags:新启动的activity该如何关联

如果A启动B,B能过通过manifest定义关联方式,A也能通过intent flags来定义B的关联方式,如果两个都有定义,那么A的intent flags优先。

Note:两种方式不是对等的,有些模式只能用manifest文件来定义,有些只能用intent flags来定义。

用manifest文件

<activity>元素的launchMode属性:

  • standard(默认模式)
    • 默认模式,系统创建新的activity实例,activity能被实例化多次,每个实例可以属于不同的tasks,一个task能包含多个实例。
  • singleTop
    • 如果activity的实例已经存在,并在task的栈顶,那么系统会调用存在实例的onNewIntent()而不是创建新的实例。activity可以被实例化多次,每个实例可以属于不同的task,一个task可以有多个实例(栈顶不是此activity的实例的task)
    • 例如,A-B-C-D,A是栈底,D是栈顶,此时又来一个intent需要启动D,如果D是standard模式,那么会变为A-B-C-D-D,然后如果D是singleTop模式,那么仍是A-B-C-D,intent会由D的onNewIntent来接收。如果此时启动B,那么不管B是什么模式,都是A-B-C-D-B
  • singleTask
    • 系统创建新的task,然而如果activity的实例已经在其他task中存在,那么系统会将intent分发给存在的实例,触发其onNewIntent(),而不是创建一个新的实例,系统只能存在一个实例,浏览器就是如此。
  • singleInstance
    • 与singleTask相同,除了系统不能启动其他activites到存在此activity的task中,此activity是task的唯一成员。

一般来说,返回键总是给用户带来上一个界面,然后当你启动singleTask模式的activity时,如果此activity实例已经在后台task中存在,那么整个task会被切到前台,此时,返回键是逐个显示刚切到前台的task中的所有activities。如下图所示:

Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack

Note:manifest中launchMode属性有可能会被intent flags所覆盖。

使用Intent flags

FLAG_ACTIVITY_NEW_TASK

与singleTask一致

FLAG_ACTIVITY_SINGLE_TOP

与singleTop一致

FLAG_ACTIVITY_CLEAR_TOP

如果activity实例已经在当前task中,启动时,此实例之上的activities都会被销毁,此实例触发onNewIntent()并处于栈顶。

FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK一般联合使用。

Note:如果launch mode是standard,那么已存在的实例也会被销毁,通过创建新的实例来替换销毁实例的位置,因为standard模式始终通过创建新实例来接收intent。

Handling affinities

affinity意味着activity隶属于哪个task。默认的,同一app的所有activities对于彼此有affinity。所以默认的,同一app的所有activities都在一个task中。然后,你也可以修改默认的affinity。不同app中的activities能共享一个affinity,或者同一个app中的activities能定义不同的affinities。

可以通过<activity>的taskAffinity属性来修改affinity,taskAffinity是唯一的字串。

两种使用affinity的场景:

  • Intent包含FLAG_ACTIVITY_NEW_TASK,一般系统会创建新的task,当然如果已存在task的taskAffinity与新启动的activity相同,那么也不会创建新的task。
  • 当allowTaskReparenting属性为true,

Tip:如果apk包含不止一个“application”,那么可以定义taskAffinity来区分。

Clearing the back stack

当用户离开task很长时间后,系统会清理除根activity之外的所有activities,当用户又重新回到这些task,那么只有根activity才会显示。

用户可以通过如下方式来修改这种默认行为:

alwaysRetainTaskState

如果为true在根activity中,那么上述默认行为不会发生,此task中所有activities都会长时间保持。

clearTaskOnLaunch

如果为true在根activity中,那么上述默认行为会在用户离开task后立即发生

finishOnTaskLaunch

与clearTaskOnLaunch类似,但是只针对某个activity,而不是整个task。根activity如果定义属性为true也会被清除。

启动一个task

同时定义"android.intent.action.MAIN""android.intent.category.LAUNCHER"的activity在桌面上有入口图标。

这个非常重要:用户可以离开这个task,也可以返回这个task通过桌面图标,所以定义这两种filiter的activites通常会初始化一个task。

singleTask和singleInstance应当在这种activity上定义,试想一下,singleTask启动的activity在一个新的task中,此时用户按Home键,如果桌面上无入口图标,那这个task将永远无法返回。

如果你真心不想用户能够返回一个activity,可以设置finishOnTAskLaunch属性。

Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack,布布扣,bubuko.com

Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack

上一篇:解决win7和2008连接windows 2003远程桌面很卡的问题


下一篇:GetWindowRect与GetClientRect 的区别[转]