android Tasks and Back Stack

Tasks and Back Stack、

转自:http://blog.csdn.net/mshopping/article/details/6527947

一个应用通常包括多个activity。每个activity应用设计为围绕针对执行用户特定的行为和可以启动其它activity。

一个Activity也可以启动别个应用的Activity。当别的应用完成,你的应用会重新激活,来自别个应用的activity看起来像是自己的应用中的一样。尽管这些Activity处于不同的应用,Android将这些activity维护到同一个task中给用户这种无缝的应用体验。

一个task是用户执行一个特定的工作与用户交互的一组特定的Activity的集合。Activity被安排到同一个栈(backstack)中,其中的activity按顺序的打开的。

桌面是绝大多数任务被启动的地方。当用户在应用启动器中触击一个应用的图标,这个应用就会回到前台。如果没有这个应用的任务存在,那么创建一个新的task,这个应用的 “main” Activity打开,并且作为这个task栈的根activity。

当当前Activity启动另一个Activity,新的Activity被推到栈顶并且占据焦点。前一个Activity保持在栈中,但是 处于stop状态。当一个activity停止掉后,系统保存他当前的用户接口的状态。当用户按BACK键,当前的Activity从栈中弹出并销毁,前一个Activity被激活。栈中的Actvity不会被重置,只会推入或者弹出。所以,backstack遵循一个后进先出的机制。

如果用户继续按BACK键,栈中的每个Activity都从栈中弹出显示前一个Activity,直到返回到桌面(或者到这个栈开始时正在运行的Activity)。当所有的Activity从栈中移出了,这个栈就不存在了。

一个Task是一个聚合单元,当用户开启一个新的任务,或者通过HOME键回到桌面,这个task就移动到后台。当task处于后台,所有的activity都处于stop状态,但是这个任务的backstack仍是完好无损的。当新的栈占据了焦点之后,这个栈会很简单的失去焦点。

因为backstack中的activity不会被重置,如果你的应用允许你启动一个特定的activity多次,创建一个新的activity的实例,并且推入栈顶。所以在这种情况下,如果用户使用BACK键导航,可能会多次看到同一个activity。

总结Activity与task的默认的行为

·        当Activity A 启动Activity B, Activity A停止了,但是系统会保存他的状态(例如滚动条的位置以及输入的文本信息)。当用户在B中按BACK键,Activity将继续他之间的状态。

·        当用户通过按HOME键的方式离开一个task,当前的Activity停止,并且这个task转到后台。系统将保持这个task的所有的activity的状态。如果稍后再继续这个task,这个task将回到前台,并且继续之间最栈顶的Activity。

·        如果用户按BACK键,当前Activity弹出栈并被销毁。栈中之前的Activity得以继续。当Activity被销毁了,系统将不再保存其状态。

·        Activity可以被实例化多次,甚至从其它的应用中实例。

保存Activity状态(Saving Activity State)

正如前面讨论的那样,当activity停止的时候,系统默认的行为会保存他的状态。这样的话,当导航到上一个Activity,他的接口会像他离开时的一样展现给用户。然而,你可以且应该在回调方法中主动保存你的状态,以避免你的Activity被销毁掉之且必须重新创建。

 

当系统停止掉你的Activity,系统可能为了重新获得内存而完全销毁掉他。当这种情况发生了,activity的状态信息会丢失掉。这种情况发生了,系统仍然知道这些activity在backstack有一个位置的,但是当activity到栈顶的时候,系统会重新创建他,而不是resume他了。为了避免丢失用户的工作,你需要实现onSaveInstanceState()主动保存你的activity状态。

管理Task(Managing Tasks)

像前面描述的一样,Android管理task与backstack的方法是,将所有的打开的activity连续的放进同一个task中,并且放到一个“后入,先出”的堆栈中,面对大多数的应用,你不必关心你的activity是如何与task关联的,不必关心你的activity是如何存在于backstack中的。然而你可能想打破这种常态的行为。也许你想要让你应用的activity被启动的时候去开启一个新的task(而不是将其放入当前的栈中);或者,当你启动一个activity的时候,你想将其转到一个已存在的他的实体中去(而不是在backstack 的栈顶创建一个新的实体);或者,当你离开这个task时,你想让你的backstack栈中除根activity的所有的activity都被清理掉。

你可以做到这些甚至更多,用<activity>的manifest元素的属性以及你传递给startActivity()的intent的flag。

关于这些,你可以用的<activity>的主要属性如下:

taskAffinity

lauchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch

主要的intent的flag如下:

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_SINGLE_TOP

定义启动模式(Defining launch modes)

Launch mode 允许你定义一个activity的新的实体与当前task是如何关联的。你可以用两种方式定义不同的启动模式:

·        使用manifest 文件

当在manifest中声明你的activity的时候,你可以指定当他启动时他如何与task关联。

·        使用intent的flag

当你调用startActivity()的时候,你可以为intent设置一个flag以声明这个新的activity应如何与当前的task关联。

照这样,如果ActivityA启动ActivityB,可以在manifest中定义B如何与当前的task如何关联,也可以在ActivityA中要求ActivityB与当前task如何关系。如果两个Activity都定义了ActivityB应该如何与当前Task关联,那么ActivityA的要求会更为荣幸的得到应用。

使用manifest文件(Using the manifest file)

当在manifest文件中声明一个activity的时候,你可以通过<activity>的lauchMode属性来指定activity应该怎样与task关联。

launchMode可以指定一个指定其activity应该如何启动到一个task中。这里有四种不同的launchMode你可以使用。

“standard”(默认模式)

默认模式。系统会从启动他的task中创建一个该Activity的新实例,并且导向他。一个Activity可以被实例化多次,每个实例可以属于不同的task,一个任务可以拥有多个实例。

“singleTop”

如果一个Activity的实例已经存在当前的task的栈顶了,系统会通过onNewIntent()方法将intent导向这个实例,而不是创建这个Activity的新实例。这个Activity可以被实例化多次,每个实例可以属于不同的task,且每个task可以拥有多个该Activity的实例(但是backstack的栈顶的activity不是已存在的该Activity的实例)。

例如:一个task的back stack包括一个根Activity A和ActivityB,C和在栈顶的D(当前栈的情况是A-B-C-D,D在栈顶)。一个D的intent到达了,如果D是”standard”的启动模式,那么一个新的实例产生,并且栈会变成A-B-C-D-D。然而,如果D的启动模式是”singleTop”的,那么intent通过onNewIntent()传给已存在的栈顶的D的实例,这时候的栈仍然是A-B-C-D。如果一个B的intent到达了,那么一个B的新实例会压入的栈中,即使B的启动模式是”singleTop”。

注:当一个Activity的实例被创建,用户可以通过BACK键回到前一个activity。但是如果是一个已存在的实例处理了Intent,那用户不能通过BACK键回到onNewIntent()之前的Activity状态了。

“singleTask”

系统创建一个新的任务,并实例化一个新的Activity对象作为其根。如果已经有一个该Activity的实例存在在一个单独的task中了,系统会将intent通过onNewIntent()发布到已存在的这个实例中去,而不是创建一个新实例。同时只能有一个Activity的实例存在。

注:尽管该实例存在于任务的根部,但是BACK键仍然返回到之前的Activity中去。

“singleInstance”

与”singleTask”一样,但是系统不能启动别个Activity到这个Activity的实例所在的task中去。这个Activity总是单一的,且是他所在的task的唯一成员。通过这个Activity启动的其它任何Activity都将单独启动一个单独的task。

 

不论一个Activity是在同一个栈中启动,还是在一个新的栈中启动,BACK键都会让用户回到前一个Activity中。然而,如果从你的task(taskA)启动一个被设置为”singleTask”启动模式的Activity,然后这个Activity可能有一个实例存在后台的,这个实例属于一个task,并且 有他自己的backstack(Task B)。在这种情况下,TaskB被带到前台去处理一个新的intent,按BACK键在回到TaskA的栈顶Activity之前,首先会导向TaskB的后台Activity。

使用Intent的flag(Using Intent flags)

当启动一个Activity的时候,你可以修改Activity与他的task的默认的关联关系,你可以通过向startActivity()传递的Intent中包含一个flag来实现。这些你可以使用来改变默认行为的flag如下:

FLAG_ACTIVITY_NEW_TASK:

在一个新的task中启动Activity。如果你启动的这个Activity已在一个task中运行了,这个Activity将随其最后一次保存的状态一起被置到前台,并且这个Activity会在onNewIntent()中接到这个请求的Intent。

这个过程和”singleTask”的启动模式一样。

FLAG_ACTIVIT_SINGLE_TOP:

如果Activity启动的是当前的Activity(在BackStack的栈顶),那么这个存在的实体会接到一个onNewIntent()的调用,而不是创建一个新的实例。

这个过程和”singleTop”的启动模式一样。

FLAG_ACTIVITY_CLEAR_TOP:

如果一个Activity已经在运行的栈中启动了,然后替代启动一个Activity新的实例的是,所有的在他上面的Activity将被销毁,并且这个Intent会被传递给这个Activity的实例的onNewIntent()中。

没有合适的lauchMode值与之对应。

 

处理affinity(Handling affinities)

 

Affinity表示Activity更应该属于哪个task。默认情况下,同一个应用的所有Activity有相同的affinity。所以,默认情况下,同一个应用的所有Activity更倾向于属于同一个task。然而你可以修改Activity默认的affinity。不同的应用的Activity可以拥有共享一个affinity。同一个应用的Activity可以分配不同的任务的affinity。

你可以通过修改<activity>元素的taskAffinity属性修改任何给定的Activity的affinity。

TaskAffinity属性是一个字符值,他必须在<manifest>被定义成在包名中唯一的,因为系统用名字来识别应用的默认的taskaffinity。

Affinity在两种情况下发生作用。

·        当intent启动一个Activity包含一个FLAG_ACTIVITY_NEW_TASK 的flag。

一个新的Activity在默认情况下属于通过startActivity()启动他的那个Activity所在的task。它被压入调用者相同的backstack中。然而,如果给startActivity()传递的intent包含一个FLAG_ACTIVITY_NEW_TASK的flag,系统将会寻找一个不同的task去安置这个新的Activity。通常他是一个新task。然而,它并一是必定是的。如果这里已存在一个与新的Activity相同的affinity的task,Activity会启动到这个task中去。如果没有存在的,那就开启一个新的task。

如果这个flag促使一个Activity属于一个新的task且用户是按HOME键离开他的,这里必须要有办法让用户导回之前的task。一些实体(像notification管理者)通常在一个扩展的task中启动,从不让他们作为自己的task的一部分,所以他们常把FLAG_ACTIVITY_NEW_TASK放到Intent中传给startActivity()。如果你有一个Activity被一个外部实体激活,而且这个激活可能会使用到这个flag,那么你要注意,用户有一个独特的方式返回到启动他的task中去,比如通过一个lancher的图标。

·        当Activity的allowTaskReparenting属性被设为true时。

在这种情况下,那个Activity可以从他启动的task移动到他的affinity的task中去,当这个task转到前台的时候。

例如:假如有一个旅游的应用,他包含一个报告选择了的城市的天气状况的Activity。他有一个与同一应用的其它Activity有相同的affinity(默认的系统的affinity)并且他允许用这个属性re-prearenting。当你的一个Activity启动了这个天气报告的Activity,他初始的属于与你的Activity相同的task。然而,当这个旅游应用的task转到了前台,天气报告的Activity被移到那个task并且显示他。

 

清理back stack(Clearing the back stack)

如果用户离开一个task较长的时间,系统清理掉除rootActivity之外的其它所有Activity。当用户返回这个task,只有rootActivity被恢复。系统的这么做是因为,经过一个相当长的时间,用户可能是放弃了之前的工作,而现在返回这个task是为了开启某项新的工作。

修改这个行为你可以使用如下一些Activity的属性:

alwaysRetainTaskState

如果一个root activity的这个属性被设为true,那么上面描述到的默认的行为将不会发生。Task将在栈中保留所有的Activity,即使过了较长一段时间。

clearTaskOnLaunch

如果task的root activity的这个属性被设为true,不论什么时候,用户离开这个task,然后回到他,这个栈会清理到rootactivity。换句话说,他是alwaysRetainTaskState的反义词。用户总是返回到这个栈的初始化状态,即使是刚刚离开这个栈。

finishOnTaskLaunch

这个属性像clearTaskOnLaunch一样,但是他仅针对一个单独的Activity,而不是整个Task。他也可以促使任何一个Activity离开,包括rootActivity。当他设为true时,这个activity只会当前会话保存部分task。当用户离开再返回这个task,他将不再重现。

启动一个task(Starting a task)

你可以设置一个Activity为一个task的入口,其方法是给出一个intentfilter 包括一个”android.intent.action.Main”作为其特别的action和一个”android.intent.category.LAUNCHER”作为特别的category。例如:

<activity... >
    <intent-filter ... >
        <actionandroid:name="android.intent.action.MAIN" />
        <categoryandroid:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

这种类型的intentfilter为activity产生一个图标和一个标签,他们将显示在应用启动器中,他给用户了一个启动这个activity的方法,以及当其启动之后任何时候回到这个任务的途径。

第二个能力很重要,必须让用户可以离开一个任务,并且可以通过Activitylauncher返回来。为些,那两个启动模式通常用来初始化一个任务,,仅当这个Activity拥有一个ACTION_MAIN和一个CATEGORY_LAUNCHER的filter时才使用”singleTask”或”singleInstance”。想象一下,假如,如果没有这个filter将有可能发生什么?一个intent启动了一个”singleTask”的Activity,初始化为一个新的task,用户在这个任务上消磨了一些时间。然后用户按HOME键,这时这个任务被发到后台,不可见了。由于 其在application的launcher中没有一个 描述,用户就没有办法回到这个task了。

这种情况下,如果你不希望用户回到某个Activity,可以设置<Activity>元素的finishOnTaskLaunch为true。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值