android task栈和activity的关系

转载自:http://blog.sina.com.cn/s/blog_7258b50e0100xogi.html
1、Task和Activity

task是能包含很多activity的栈。 默认情况下,一个activity启动另外一个activity时,两个activity是放在同一个task栈中的,第二个activity压入第一个 activity所在的task栈。当用户按下返回键时,第二个activity从栈中弹出,第一个activity又在当前屏幕显示。这样,从用户角度 来看,这两个activity就好像是属于同一个应用程序的,即使第二个activity是属于另外一个应用程序的。当然,这是指默认情况下。 task栈包含的是activity的对象。如果一个activity有多个实例在运行,那么栈中保存的是每个实例的实体。栈中的activity不会重 新排列,只有弹出和压入操作。 一个task中的所有activity都以整体的形式移动。整个task可以被移到前台或后台。打个比方,当前的task包含4个activity–当前 activity下面有3个activity。当用户按下HOME键返回到程序启动器(application launcher)后,选择了一个新的应用程序(事实上是一个新的task),当前的task就被转移到后台,新的task中的根activity将被显 示在屏幕上。过了一段时间,用户按返回键回到了程序启动器界面,选择了之前运行的程序(之前的task)。那个task,仍然包含着4个 activity。当用户再次按下返回键时,屏幕不会显示之前留下的那个activity(之前的task的根activity),而显示当前 activity从task栈中移出后栈顶的那个activity。 刚刚描述的行为是默认的activity和task的行为。有很多方法能够改变这种行为。activity和task之间的联系,以及task中的 activity的行为可以通过intent中的标记以及在manifest中的<activity>元素的属性控制。其中,主要的 Intent标记有:

l FLAG_ACTIVITY_NEW_TASK

l FLAG_ACTIVITY_CLEAR_TOP

l FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

l FLAG_ACTIVITY_SINGLE_TOP

主要的<activity>属性有:

l taskAffinity

l launchMode

l allowTaskReparenting

l clearTaskOnLaunch

l alwaysRetainTaskState

l finishOnTaskLaunch

默 认情况下,一个应用程序中的所有activity都有一个affinity–这让它们属于同一个task。然而,每个activity可以通 过<activity>中的taskAffinity属性设置单独的affinity。不同应用程序中的activity可以共享同一个 affinity,同一个应用程序中的不同activity也可以设置成不同的affinity。affinity属性在2种情况下起作用:当启动 activity的Intent对象包含FLAG_ACTIVITY_NEW_TASK标记,或当activity的allowTaskReparenting被设置成true。

FLAG_ACTIVITY_NEW_TASK标记

当 传递给startActivity()的Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统会为需要启动的activity 寻找与当前activity不同的task。如果要启动的activity的affinity属性与当前所有的task的affinity属性都不相同, 系统会新建一个带那个affinity属性的task,并将要启动的activity压到新建的task栈中;否则将activity压入那个 affinity属性相同的栈中。

allowTaskReparenting属性

如果一个activity的allowTaskReparenting属性为true,那么它可以从一个task(TASK1)移到另外一个有相同affinity的task(TASK2)中(TASK2带到前台时)。

如果一个.apk文件从用户角度来看包含了多个“应用程序”,你可能需要对那些activity赋不同的affinity值。

2、运行模式

activity的launchMode属性可以有四种值:

l “standard” (默认)

l “singleTop“

l “singleTask“

l “singleInstance“

这4种模式可以按4种分类来区分,以下假设位于task1中的activity1启动activity2:

模式分类

包容activity2的task

一个activity是否允许有多个实例

activity是否允许有其它activity共存于一个task

对于新的intent,是否总是实例化activity对象

standard

如果不包含FLAG_ACTIVITY_NEW_TASK标记,则activity2放入task1,否则按前面讲述的规则为activity2选择task

可被多次实例化,同一个task的不同的实例可位于不同的task中,每个task也可包含多个实例

允许

是的。当接收到新的intent时,总是会生成新的activity对象。

singleTop

同standard

同standard

允许

已存在的activity对象,如果位于目标task的栈顶,则该activity被重用,如果它不位于栈顶,则会实例化新的activity对象

singleTask

将activity2放到task1栈底

不能有多个实例。由于该模式下activity总是位于栈顶,所以actvity在同一个设备里至多只有一个实例

允 许。singleTask模式的activity总是位于栈底位置。目标activity实例已存在时,如果该实例刚好位于task栈顶,则接收 intent,否则到来的intent将会被丢弃,但该可以响应该intent的那个activity所在的task将会被移到前台。

 

singleInstance

同singleTask

同singleTask

不允许与其它activity共存于一个task。如果activity1的运行在该模式下,则activity2一定与activity1位于不同的task

 

对于新到的intent,如果是由新创建的activity对象来接收,则用户可以通过返回键回到之前的activity;如果是由已存在的activity来接收,则用户无法通过返回键返回到接收intent之前的状态。

3、清空栈

当用户长时间离开task(当前task被转移到后台)时,系统会清除task中栈底activity外的所有activity。这样,当用户返回到task时,只留下那个task最初始的activity了。

这是默认的情况,<activity>中有些属性可以改变这种行为。

l alwaysRetainTaskState属性

如果栈底activity的这个属性被设置为true,刚刚描述的情况就不会发生。task中的所有activity将被长时间保存。

l clearTaskOnLaunch属性

如 果栈底activity的这个属性被设置为true,一旦用户离开task,则task栈中的activity将被清空到只剩下栈底activity。这 种情况刚好与alwaysRetainTaskState相反。即使用户只是短暂地离开,task也会返回到初始状态(只剩下栈底acitivty)。

l finishOnTaskLaunch属性

这 个属性与clearTaskOnLaunch相似,但它只对单独的activity操作,而不是整个task。它可以结束任何activity,包括栈底 的activity。当它设置为true时,当前的activity只在当前会话期间作为task的一部分存在,当用户退出activity再返回时,它 将不存在。

另外还有一种方法能将activity强行从stack中移出。如果intent对象包含 FLAG_ACTIVITY_CLEAR_TOP标记,当目标task中已存在与接收该intent对象的activity类型相同的activity实 例存在时,所有位于该activity对象上面的activity将被清空,这样接收该intent的activity就位于栈顶,可以响应到来的 intent对象。如果目标activity的运行模式为standard,则目标activtiy也会被清空。因为当运行模式为standard时,总 会创建新的activity对象来接收到来的intent对象。

FLAG_ACTIVITY_CLEAR_TOP标记常常和FLAG_ACTIVITY_NEW_TASK一起使用。用2个标记可以定位已存在的activity并让它处于可以响应intent的位置。

4、启动任务(Task)

Intent filter中有”android.intent.action.MAIN” action和”android.intent.category.LAUNCHER” category的activity将被标记为task的入口。带有这两个标记的activity将会显示在应用程序启动器(application launcher)中。

第二个比较重要的点是,用户必须能够离开task并在之后返回。因为这个原因,singleTask和 singleInstance这两种运行模式只能应用于含有MAIN和LAUNCHER过滤器的activity。打个比方,如果不包含带MAIN和 LAUNCHER过滤器,某个activity运行了一个singleTask模式的activity,初始化了一个新的task,当用户按下HOME键 时,那个activity就被主屏幕“挡住”了,用户再也无法返回到那个activity。

类似的情况在 FLAG_ACTIVITY_NEW_TASK标记上也会出现。如果这个标记会新建一个task,当用户按下HOME键时,必须有一种方式能够让用户返回 到那个activity。有些东西(比如notification manager)总是要求在外部task中启动activity,在传递给startActivity的intent中总是包含 FLAG_ACTIVITY_NEW_TASK标记。

对于那种不希望用户离开之后再返回activity的情况,可将finishOnTaskLaunch属性设置为true。


实战篇:

    场景1:我们需要一个activity一直存活,且状态一直保留我们可以让该activity独占一格task栈,如下设置activity属性。

     android:launchMode="singleInstance" android:taskAffinity="com.test"

     把launchMode和taskAffinity结合起来用会有异想不到的效果。

    场景2:我们需要一个activity  ——“A” 存活于task栈并且一旦返回A,那么A之上的所有activity都会被销毁。如下设置activity属性。

     android:launchMode="singleTask"  android:clearTaskOnLaunch="true"

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个应用往往包含很多activities.每个activity都应围绕着用户可执行的特定动作来设计,并且可以启动其它activitie.例如,一个email应用可能可能有一个显示新邮件列表的activity.当用户选择一个邮件,一个新的activity被打开以显示邮件内容. 一个activity也可以打开同一设备上存在于其它应用的activitie,例如,如果你的应用想要发送一个邮件,你可以定义一个intent来执行一个"send"动作并包含一些数据,比如一个地址和一条信息.另一个应用中的一个叫嚣自己可以处理这种intent的activity就被打开(如果有多个activitie支持同样的intent,那么系统会让用户选择一个).当email被发送后,你的activity被恢复并且看起来发送邮件的activity好像是你的应用的一部分.即使那个activitie可能来自不同的应用,Android也靠着把两个activity保存在同一任务中来实现这种无缝的用户体验. 一个任务是用户在执行某种工作时所交互的activitie的集合.activitie们放置在一个("后退")中,按照打开的顺序排列. 设备的Home屏是大多数任务的开始场所.当用户触摸在应用启动台中的图标(或一个home屏上的快捷方式)时,应用的任务就来到了前台.如果没有这个应用的已存在的任务(这个应用最近没有被使用),那么一个新的任务被创建并且这个应用的"main"activity被作为的根activity打开. 当当前的activity启动了另一个activity,新的activity被放置在顶并拥有焦点.先前的activity依然保存在中,但是停止了.当一个activity停止时,系统保存了它的用户界的当前状态.当用户后退按钮时,当前的activity被从顶弹出(activity被销毁了)并且先前的activity被恢复了.中的Activities永不会被重新排列,只是入或出—当被当前activity启动时就入,当用户使用后退按钮离开它时就出.如此,后退也是一个后进先出的. 下图展示了工作的变化过程.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值