Android task和back stack详解(官方文档翻译)

时间:2014-07-16 20:59:16   收藏:0   阅读:324

一个应用往往包含很多activities.每个activity都应围绕着用户可执行的特定动作来设计,并且可以启动其它activitie.例如,一个email应用可能可能有一个显示新邮件列表的activity.当用户选择一个邮件,一个新的activity被打开以显示邮件内容.

  一个activity也可以打开同一设备上存在于其它应用的activitie,例如,如果你的应用想要发送一个邮件,你可以定义一个intent来执行一个"send"动作并包含一些数据,比如一个地址和一条信息.另一个应用中的一个叫嚣自己可以处理这种intentactivity就被打开(如果有多个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启动时就入栈,当用户使用后退按钮离开它时就出栈.如此,后退栈也是一个后进先出的栈.

 

 

 

下图展示了工作栈的变化过程.

bubuko.com,布布扣

 

  如果用户继续后退,那么栈中的各activity被弹出来展示上一个,直到用户退到Home(或到达任务开始时运行的那个activity).当所有的activitie都从棧种移除,任务就不再存在.

  一个任务是一个有聚合力的单元,它可以在用户启动一个新的任务或回到home屏时被整体地移到后台.当位于后台时,任务中的所有的activitie都处于停止,但是任务的后退栈却保存完整—当任务被另一个任务取代时,仅仅是失去了焦点.见图2:

bubuko.com,布布扣

 

2. 两个任务:任务B到了前台,任务A于是被打入后台,伺机恢复.

 

  一个任务可以再回到前台,于是用户可以获得他离开时的模样.举个例子,当前的任务(任务A)有三个activitie在其栈中—两个在下面.用户按下Home 按钮,然后又启动一个新的应用.当Home屏出现时,任务A到了后台.当新应用启动时,系统为这个应用开始了一个任务(任务B).当使用完新应用时,用户再次回到了Home屏然后选择了启动任务A的那个应用.现在,任务A来到了前台—其棧中所有的三个activitie都完整保留并且位于顶层的activity被恢复.此时,用户也可以再回到home屏然后选择任务B的应用于是回到任务B(或通过长按Home 按钮以显示最近的任务然后选择它)

注:多个任务可以同时存在于后台.然而,如果用户在同一时刻运行多个后台任务,系统可能会销毁后台activitie来釋放内存,从而导致activity状态的丢失.

  因为后退栈中的activitie从不会被重排,如果你的应用允许用户从不只一个activity启动一个特殊的activity,一个新的activity的实例会被创建并压入栈中(而不是把这个activity的当前实例弄到前台来).所以,你的应用中的一个activity可能被多次实例化(甚至是从不同的任务),如图3所示.同样的,如果用户使用后退按钮向后导航,activity的每个实例都会按照打开的顺序重新显现(每个都保持它们自己的状态).然后,你如果不想某个activity被实例化多次,你可以改变这种行为.后面会讲到如何做.

 

 bubuko.com,布布扣

 

3.一个activity被实例化多次.

 

下面总结一下下activity和任务的默认行为:

 

保存Activity的状态

 

  如前一节所述,系统默认下会在activity停止的时候保存其状态.如此一来,当用户导航到前一个activity时,其用户介面显示得跟离开时一样.然后,你可以—并且应该—提前使用你的activity的回调方法们保持它的状态,因为activity可能会被销毁然后被重新创建.当系统停止了你的一个activitie(比如当新的activity启动或任务被移到后台),系统可能为了释放内存会完全销毁那个activity.当这事发生时,activity的状态丢失.如果真发生了这种现象,系统依然知道那个activity在后退栈中占有一个位置,但是当activity被弄到前台时,系统必须重新创建它(而不是仅仅恢复它).为了避免丢掉用户的工作,你应该通过实现activityonSaveInstanceState()c来提前保存状态.

  关于保存activitystate的更多知识,请观http://blog.csdn.net/nkmnkm/article/details/7101178


管理任务们

  Android管理任务和后退栈的方式,如前面文章所述—通过把所有接连启动的activity放在同一个任务中并且是同一个后进先出的栈中—在大多数应用中工作得很好并且你无需关心你的activity如何与任务相关连或如何在后退栈中存在.然而,你可能决定要打破这种正常的行为.可能你想在你应用的activity启动时开始一个新的任务(而不是放置到当前栈中);或者,当你启动一个activity,你想把已经运行的它的一个实例提到前台来(而不是创建一个新的实例放在后退栈的顶端);或者,你希望当用户离开任务时,你的后退栈清除除了根activity以外所有的activity.

  可以做这些事情,甚至更多事情,通过设置manifest中<activity>的属性和传到startActivity()的intent的flag.

在这一点上,你可以设置的最重要的<activity>属性有:

taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch



可以使用的最重要的intent flag:

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_SINGLE_TOP

 

注意:大多数应用不应改变activity和任务的默认行为.如果你确定必须要改变默认行为,你必需小心并且保证测试了activity在启动时和后退导航到它时的可用性.确保测试了与用户习惯相冲突的导航行为.

 

定义启动模式

  启动模式使你可以定义新的activity如何与当前的任务相关联.有两种方法来定义不同的启动模式:

  同样的,如果ActivityA 启动ActivityBActivityB可以在它的manifest中定义如何与当前的任务关联(如果真的存在)并且ActivityA 也可以请求让ActivityB如何与当前的任务关联.如果两个activity都定义了ActivityB如何与任务关联,那么ActivityA的请求(intent中定义)优先于ActivityB的请求(在它的manifest中定义)



注:一些启动模式可以用在manifest中但不能用在intentflag上,同样的,一些启动模式可以用在intentflag上但不能用在manifest中.

使用manifest文件

  当在你的manifest文件中声明一个activity时,你可以使用<activity>元素的launchMode属性指定activity如何与一个任务关联.



  launchMode属性指明了activity如何启动到一个任务中去.有四种不同的启动模式你可以用于指定给launchMode属性:

 

接上文,关于后退栈,先举个例子:

 

  Android浏览器应用声明网页浏览activity必须在它自己的任务中打开—通过在<activity>元素中指定singleTask启动模式.这表示如果你的应用发出一个intent来打开Android浏览器,它的activity不会放到你的应用所在的任务中.代替的是,可能一个新的任务为浏览器启动,或者,如果浏览器已经运行于后台,它所在的任务就被弄到前台并接受这个intent

  不论一个从一个新任务启动activity还是在一个已存在这种activity的任务中启动,后退键总是能后退到前一个activity.然而,如果你在任务A中启动一个声明为singleTask模式的activity,而这个activity可能在后台已有一个属于一个任务(任务B)的实例.任务B于是被弄到前台并处理这个新的intent.那么此时后退键会先一层层返回任务BActivity,然后再返回到任务A的顶端activity图 4演示了这种情形.

bubuko.com,布布扣

4.演示一个"singleTask"启动模式的acitvity如何被添加到一个后退栈中.如果这个activity已经是一个后台任务(任务B)自己的栈的一部分,那么整个后退栈被弄到前台,位于当前任务 (任务A)的上面.

 

注:你使用launchMode属性的指定的actvitiy的行为可以被intent的flag覆盖.

 

使用 Intentflags

 

  当启动一个activity时,你可以在给startActivity()的intent中包含flag以改变activity与任务的默认关联方式.你可以用来改变默认行为的flag有:

 

 

处理任务亲和力

  亲和力表明了一个activity"心仪"哪个任务.默认下,属于同一个应用的所有activitie之间具有相同的任务亲和力.所以,默认下,一个应用的所有activitie首选属于同一任务.然而,你可以修改一个activity的默认任务亲和力.定义于不同应用的Activitie可以具有相同的任务亲和力,或者同一应用中的activitie可以分配不同的任务亲和力.

  你可以使用<activity>元素的taskAffinity属性来修改一个activity的任务亲和力.taskAffinity属性使用字符串作为值,这个字符串必须与在<manifest>中声明的默认包名不同,因为系统使用包名来标识默认的任务亲和力.



  亲和力在以下两种情况起作用:



小提示::如果一个.apk文件包含多个从用户角度所认为的"应用",你可能想通过为activity指定属性taskAffinity来使它们连接到不同的"应用"



清空后退栈

  如果用户离开了一个任务很长一段时间,系统会清空任务中除了根activity之外的所有其它activity.当用户重新返回这个任务时,只有根activity被恢复.系统之所以这样做,是因为经过一大段时间之后,用户很可能已抛弃掉他们已经做的并且回到任务开始做一些新的事情.

  有一些activity属性你可以用来改变这种行为:

启动一个task

  你可以设置一个activity为一个任务的入口,通过给它一个值为"android.intent.action.MAIN"的intent过滤器"和一个值为"android.intent.category.LAUNCHER"的过滤器.例如:

<activity... >

<intent-filter... >

<actionandroid:name="android.intent.action.MAIN" />

<categoryandroid:name="android.intent.category.LAUNCHER" />

</intent-filter>

...

</activity>



  一个intent这种类型的过滤器导致activity的一个图标和标签被显示于应用启动界面上.使得用户可以启动这个activity并且再次回到这个任务.

  这第二个能力是很重要的:用户必须能离开一个任务并且之后还能通过启动器回来.为此,两种使得activity永远在新任务中启动的启动模式:"singleTask"和"singleInstance",应该只在当activity具有ACTION_MAIN和CATEGORY_LAUNCHER过滤器时使用.想像一下,例如,如果没有这些过滤器将会发生什么:一个intent启动一个"singleTask"activity,在一个新的任务中初始化,并且用户在这个任务中忙乎了一些时间.然后用户按下HOME按钮.任务现在被移到后台并且不可见了.因为这个activity不是应用的启动activity,用户就再也没有办法回到这个任务了.

  但遇到那些你不希望用户能够回到一个activity的情况时怎么办呢?有办法:设置<activity>元素的finishOnTaskLaunch属性为"true"!

 

摘自:http://blog.csdn.net/niu_gao/article/details/7284470

Android task和back stack详解(官方文档翻译),布布扣,bubuko.com

原文:http://www.cnblogs.com/veins/p/3836378.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!