Tasks and Back Stack
原文地址:http://docs./guide/topics/fundamentals/tasks-and-back-stack.html 翻译:無語 @ 2012.06.07?
任务栈和返回堆栈一个应用程序通常包含多个Activity.每个Activity都必须设计成一种特定的操作, 用户可以通过该操作去实现某项功能,并且操作其他的Activity.例如.一个电子邮件的应用程序可能有一个Activity,用于展现出新的电子邮件 列表,当用户选择了一个电子邮件,就打开一个新的Activity以查看该电子邮件.
图 3. activity A 被实例化多次。
导航设计 关于 Android 中应用程序间导航的详情,请参阅 Android 导航 设计指南. 保存Activity状态如上所述,系统默认会在Activity 停止时保存其状态.这样,当用户返回时,用户的界面能与离开时显示得一样.不过,你可以,也应该使用用回调方法主动地保存Activity的状态,以便应对Activity被销毁并重建的情况. 当系统停止一个Activity 运行后(比如启动了一个新Activity 或者Task 转入后台),系统在需要回收内存的时候有可能会完全销毁该Activity.这时,该Activity的状态信息将会丢失.就算这种情况发生,该 Activity 仍然会存在于Back Stack中.但是当它回到栈顶时,系统将必须重建它(而不是恢复).为了避免用户工作内容的丢失,你应通过实现Activity 的 onSaveInstanceState() 方法来主动保存这些内容. 关于如何保存Activity 状态的详情,请参阅 Activities. 管理多个Task如上所述,把所有已经启动的Activity 相继放入同一个Task 中以及一个“后入先出”栈,Android 管理Task和Back Stack 的这种方式适用于大多数应用,你也不用去管理你的Activity 如何与Task关联及如何弹出Back Stack .不过,有时候你或许决定要改变这种普通的运行方式.也许你想让某个Activity启动一个新的Task(而不是被放入当前Task中),或者,你想让 activity 启动时只是调出已有的某个实例(而不是在Back Stack 顶创建一个新的实例)或者,你想在用户离开Task 时只保留根Activity,而Back Stack 中的其它 Activity 都要清空, 你能做的事情还有很多,利用 " <activity> manifest 元素的属性和传入 startActivity() 的 intent 中的标识即可。 这里,你可以使用的 <activity> 属性主要有:
警告: 大多数应用不应该改变 Activity 和 Task 默认的工作方式。 如果你确定有必要修改默认方式,请保持谨慎,并确保 Activity 在启动和从其它 Activity 用返回键返回时的可用性.请确保对可能与用户预期的导航方式相冲突的地方进行测试. 定义启动模式启动模式定义了一个新的Activity 实例与当前Task 的关联方式。定义启动模式的方法有两种: 当你在 manifest文件中声明一个Activity 时,可以指定它启动时与Task 的关联方式。 调用 startActivity() 时,可以在 Intent 中包含一个标识,用于指明新Activity 是如何(是否)与当前Task 相关联。 同样的,如果 Activity A 启动了Activity B,则 Activity B 可以在 manifest 中定义它如何与当之前的Task 关联(如果存在的话), 并且,Activity A 也可以要求 Activity B 与当前 task 的关联关系.如果两个Activity都定义了,则 Activity A 的请求(intent 中定义)会比Activity B 的定义(在 manifest 中)优先. 注意: manifest 文件中的某些启动模式在 intent 标识中并不可用,反之亦然,intent 中的某些模式也无法在 manifest 中定义。 配置 manifest 清单文件在manifest文件中声明Activity 时,你可以使用 <activity> 元素的 launchMode 属性来指定Activity与Task的关系. launchMode 属性指明了Activity启动Task的方式。 launchMode 属性可设置四种启动模式: "standard" (默认模式): "每次访问实例化新的Activity" 默认,系统在启动Activity 的Task 中创建一个新的Activity 实例,并且把 intent 传送路径指向它.该Activity 可以被实例化多次,各个实例可以属于不同的Task,一个Task 中也可以存在多个实例. "singleTop" "每次访问,看栈顶元素目标对象,是则返回,不再实例化,否则,还是实例化新的Activity." 如果Activity的一个实例已经存在于当前Task的栈顶,该系统就会使用onNewIntent()方 法通过intent 传递给已有实例,而不是创建一个新的Activity 实例.Activity 可以被实例化多次,各个实例可以属于不同的Task,一个Task中可以存在多个实例(但只有Back Stack的Activity 实例不是该Activity 的). 例如,假设Task 的 Back Stack 中包含了根Activity A 和 Activities B、C、D(顺序是 A-B-C-D; D在栈顶. 这时候传过来的是启动D的intent,如果D的启动模式是默认的"standard",则会启动一个新的实例,栈的内容就会变为 A-B-C-D-D.但是!!!但是,如果 D 的启动模式是 "singleTop",则已有的D的实例会通过onNewIntent():接收这个 intent,因为该实例位于栈顶——栈中内容仍然维持 A-B-C-D 不变.当然,如果 intent 是要启动 B 的,则 B 的一个新实例还是会加入栈中,即使 B 的启动模式是"singleTop"也是如此. 注意: 一个Activity 的新实例创建完毕后,用户可以按返回键返回前一个activity.但是当Activity 已有实例正在处理刚到达的intent 时,用户无法用返回键回到onNewIntent()中 intent 到来之前的Activity 状态. "singleTask" "保证activity实例化一次,单任务,由此所开启的活动和本活动位于同一task中" 系统将创建一个新的Task,并把Activity 实例作为根放入其中.但是,如果Activity 已经在其它Task 中存在实例,则系统会通过调用其实例的onNewIntent() 方法把 intent传给已有实例,而不是再创建一个新实例. 此 activity 同一时刻只能存在一个实例. 注意: 虽然Activity启动了一个新的Task,但用户仍然可以用返回键返回前一个activity. "singleInstance" "保证Activity实例化一次,单实例,由此所开启的Activity在新的task中,和本活动id不一致." 除了系统不会把其它Activity 放入当前实例所在的 Task 之外,其它均与"singleTask"相同,Activity 总是它所在Task 的唯一成员;它所启动的任何Activity 都会放入其它Task 中. 举一个事例:Android 的浏览器应用就把 web 浏览器Activity 声明为总是在它自己独立的Task 中打开——把 activity设为singleTask模 式.这意味着,如果你的应用提交 intent 来打开 Android 的浏览器,则其 activity不会被放入你的应用所在的Task 中.取而代之的是,或是为浏览器启动一个新的Task;或是浏览器已经在后台运行,只要把Task 重新调入前台来处理新 intent 就可以. 无论Activity是在一个新的Task 中启动,还是位于其它已经存在的Task中,用户总是可以返回键返回到前一个Activity 中.但是,如果你启动了一个启动模式设为singleTask的 activity,且有一个后台 task 中已存在实例的话,则这个后台 task 就会整个转到前台.这时,当前的Back Stack就包含了这个转入前台的Task 中所有的Activity,位置是在栈顶.图4所描述的就是这一种场景
在manifest 文件中使用启动模式的详情,请参阅<activity>元素文档,其中详细描述了launchMode属性及其可用值. 注意: 你使用launchMode 属性为Activity设置的模式可以被启动Activity的intent标识所覆盖,这将在下一章节具体说明。 使用 Intent 标识在启动Activity 时,你可以在传给 startActivity() 的 intent 中包含相应标识,用于修改Activity 与Task 的默认关系。这个标识可以修改的默认模式包括:
FLAG_ACTIVITY_CLEAR_TOP 经常与 FLAG_ACTIVITY_NEW_TASK 结合起来一起使用.这些标识定位在其它Task中已存在的Activity,再把它放入可以响应 intent的位置上. 注意:如果Activity 的启动模式配置为"standard",它就会先被移除出栈,再创建一个新的实例来处理这个 intent,因为启动模式为 "standard" 时,总是会创建一个新的实例。 affinities处理affinity指明Activity对于哪些Task亲和力更高.默认情况下,同一个应用中的所有 activity 都拥有同一个affinity 值. 因此,在同一应用程序中的所有Acttivity都喜欢在相同的Task.不过,你可以修改Activity 默认的 affinity 值.不同应用中的Activity 可以共享同一个affinity 值,同一个应用中的Activity也可以赋予不同的Task affinity值. 你可以使用<activity>元素的taskAffinity 属性修改Activity的affinity taskAffinity 属性是一个字符串值,必须与<manifest> 元素定义的包名称保证唯一性,因为系统把这个包名称用于标识应用的默认Task affinity值. 下面的两种情况下affinity将会发挥作用:
的Activity 所在Task 中,且压入调用者所在的Back Stack 顶栈.不过,如果传给startActivity() 的 intent 包含了FLAG_ACTIVITY_NEW_TASK 标识,则系统会查找另一个Task并将新Activity 放入其中.一般情况下会新开一个任务,但并非一定如此.如果一个已有Task的affinity值与新 Activity的相同,则Activity 会放入该Task.如果没有,则会新建一个新Task.
startActivity() 的 intent 中.如果你的Activity 可以被外部应用带此标识来启动,请注意用户会用其它方式返回启动Task,比如通过应用图标(Task 的根 Activity 带有一个CATEGORY_LAUNCHER intent过滤器;参阅下节#启动task).
提示:如果一个.apk文件中包含了多个“application”,从用户的角度来看,你可能想使用taskAffinity 属性来分配每个“application”中 activity 的 affinity 值. 清除Back Stack如果用户长时间离开某个Task,系统将会仅保留一个根Activity,而把其它Activity 都清除掉.当用户返回Task 时,只有根Activity 会被恢复.系统的这种行为,是因为经过了很长时间后,用户是要放弃之前进行的操作,返回Task 是为了开始新的操作. 可以使用Activity的某些属性来改变这种行为:
启动Task你可以通过发送一个指定动作和类别为 "android.intent.action.MAIN"、category 为 "android.intent.category.LAUNCHER" 发送 intent来指定某个Activity为Task的入口,例如: <activity ... >
<intent-filter ... > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> ... </activity> 这种intent过滤器将会让此Activity 的图标和标签作为应用启动图标来显示,用户可以启动此Activity,并且在之后任何时候返回其启动时的Task. 第二个能力非常重要.用户必须能离开一个Task ,之后能再回来使用这个启动Task 的Activity.由于这个原因,标明Activity每次都会启动Task的这两种启动模式 "singleTask" 和 ""singleInstance"应仅用于ACTION_MAIN 和CATEGORY_LAUNCHER过滤器的Activity才能使用.例如,如果缺少过滤器会发生怎样的问题:某个intent启动了一个 "singleTask" activity,并新建了一个Task,用户在此Task中工作了一段时间.然后他按了Home键,Tassk 就转入后台,变为不可见状态,这时用户就无法再回到Task了,因为它在application launcher中配置对应的属性. 对于那些你不希望用户能够返回的Activity,将<activity>元素的finishOnTaskLaunch 设置为"true" 即可.详细请(参阅 #清除Back Stack) |
|
来自: JUST SO LAZY > 《java\android》