Task和activity的lauchMode

一、Task概述

1、什么是Task?

一个Task是用户在执行某种工作时所需要的activities的集合.activities放置在一个栈("back stack")中,按照启动的顺序排列.

一个任务栈中的activities可以来自于不同的应用程序,可以包含一个应用程序的某个activity的多个实例。

处于栈顶的Activity处于交互状态,其他的Activity处于Stop状态。

2、Task的创建

1)设备的Home屏是大多数任务的开始场所。当用户触摸在应用启动界面的图标(或一个home屏上的快捷方式)时,应用的任务就来到了前台。如果没有这个应用已存在的任务(这个应用最近没有被使用),那么一个新的任务被创建并且这个应用的"main"activity被作为栈的根activity打开。

2)当由一个activityA启动一个lanchMode设置为singleTask的activityB时,如果activityB实例不存在,并且activityB和activityA的taskAffinity值不同,则会创建一个新的Task,并且activityB作为栈的根activity。

3)当由一个activityA启动一个lanchMode设置为singleInstance的activityB时,如果activityB实例不存在,则会创建一个新的Task,并且该Task中只会有activityB一个activity。

3、切换任务,home键的默认行为

单击home键,可以将当前任务切换到后台,长按Home键,可以查看和选择最近的任务。

4、结束Task

当Task的根activity销毁时,该Task也被销毁。

二、Affinity吸附值或亲和值

一个应用程序application,一个activity和一个task都有affinity。

application和activity的Affinity可以通过android:taskAffinity属性指定,taskAffinity属性使用字符串作为值

application未明确设置时,其吸附值为应用程序的包名。

activity未明确设置时,其吸附值与application的吸附值相同。

task的吸附值由根activity决定。

Affinity在以下两种情况起作用:

  • 当启动一个activityintent包含FLAG_ACTIVITY_NEW_TASK标志.

      一个新启动的activity默认是在调用startActivity()activity所在的任务中安置.然而,如果传给startActivity()intent包含了FLAG_ACTIVITY_NEW_TASK标志,系统就会查找另一个能安置这个新activity的任务.通常,它会是一个新任务.然而但是,并不是必须这样做.如果有一个已存在的任务具有与新activity相同的吸附值,那么这个activity就被启动并安置到这个已存在的任务中.如果没有这样的任务,才开始一个新的任务.

      如果这个标志导致了一个activity在一个新的任务中启动然后用户按下了HOME键离开了这个新任务,那么必须有一些方法使得用户可以重新回到这个任务.一些实体(比如通知管理器)总是在一个另外的任务中启动activity而从不作为自己任务的一部分,于是它总是把FLAG_ACTIVITY_NEW_TASK设置到传给startActivity()intents中.如果你有一个activity可以被外部实体使用这个标志调用,应小心用户可能用一个独立的方法回到这个启动的任务,比如使用启动图标(任务的根activity有一个CATEGORY_LAUNCHER intent过滤器),也就是说,只要使用了相同的亲和力,用户就能回到这个已启动的任务中.

  • 当一个activityallowTaskReparenting属性为"true"时.

       用来标记Activity能否从启动它的Task移动到有着相同affinity的Task(当这个Task进入到前台时)——“true”,表示能移动,在此情况下,activity可以从启动它的任务移动到一个具有相同吸附值的任务中,当后一个任务来到前台时。“false”,表示它必须呆在启动时呆在的那个Task里。如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。

      例如,假设一个报告所选城市的天气状况的activity是作为一个旅游应用的一部分.它与同一个应用中的其它activity具有相同的亲和值(默认的application亲和值)并且它被允许重认父母.当你的一个activity启动了这个天气预报activity,它起初是与你的actvity属于同一个任务.然而,当旅游应用的任务进入前台时,天气预报activity就被重新分配到这个任务并在其只显示.

     一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着相同affinity的Task中。典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。


     Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity决定。因此,根据定义,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和“singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模式。

三、Task和Activity的默认行为

Android管理任务和后退栈的默认方式,把所有接连启动的activity放在同一个任务中并且是同一个后进先出的栈中。

1、Back键行为

当前的activity启动了另一个activity,新的activity被放置在栈顶并拥有焦点。先前的activity依然保存在栈中,但是停止了。当一个activity停止时,系统保存了它的用户界面的当前状态。当用户点击后退按钮时,当前的activity被从栈顶弹出(activity被销毁了)并且先前的activity被恢复了。栈中的activities永不会被重新排列,只会进行入栈或出栈行为——当被当前activity启动时就入栈,当用户使用后退按钮离开它时就出栈。如此,后退栈也是一个后进先出的栈。



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

例如,有两个应用程序A和B,当按A1->A2->B1->B2依次启动时,A1,A2,B1,B2会处于同一个任务栈,A1处于栈底,按Back键会依次销毁B2,B1,A2,当在A1按Back键时,会返回到Home界面,此时A2不会被销毁。当再次按A程序的启动图标时,任务会回到前台,此时任务栈中只有A1。

有两个应用程序A和B,当按A1->A2->B1->B2依次启动时,然后按Home键回到桌面,此时打开应用B的图标,会创建新的任务,B1为根Activity。

2、任务的整体性和Home键切换任务

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



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

注:多个任务可以同时存在于后台,然而当系统内存不足时,系统会销毁后台的activities来释放内存,从而导致acitivity状态的丢失。

3、任务中一个acitivity的多个实例

因为后退栈中的activities从不会被重排,如果你的应用允许用户从不只一个activity启动一个特殊的activity,一个新的activity的实例会被创建并压入栈中(而不是把这个activity的当前实例弄到前台来).所以,一个应用中的一个activity可能被多次实例化(甚至是从不同的任务)如果用户使用后退按钮向后导航,activity的每个实例都会按照打开的顺序重新显现(每个都保持它们自己的状态).然而,如果不想某个activity被实例化多次,可以通过设置activity的启动模式或通过设置Intent的flag来避免这种情况。

4、总结:activity和任务的默认行为

  • ActivityA启动ActivityBActivityA停止,但是系统保存它的状态(比如滚动条的位置和表单中输入的文本).如果用户在ActivityB中按下了后退按钮,ActivityA以保存的状态恢复.

  • 当用户按下Home按钮离开了一个任务,当前的activity停止同时它的任务进入后台.系统保持任务中每个activity的状态.如果用户后来运行了这个任务的应用而恢复了这个任务,任务回到前台并使栈顶端的activity恢复.

  • 如果用户按下了后退按钮,当前的activity从栈中弹出并被销毁.前一个activity被恢复.当一个activity被销毁时,系统不再保持activity的状态.

  • Activitie可以被多次实例化,即使是从另外的任务.

四、管理Task和改变Activity的启动方式

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

可以设置的最重要的<activity>属性有:taskAffinity,launchMode,allowTaskReparenting,clearTaskOnLaunch,alwaysRetainTaskState,finishOnTaskLaunch

可以使用的最重要的Intent的flag

FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_CLEAR_TOP,FLAG_ACTIVITY_SINGLE_TOP。

1、activity的启动模式

当在manifest文件中声明一个activity时,可以使用<activity>元素的launchMode属性指定activity的启动模式,表示如何与一个任务关联,决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。

1)standard 默认模式

创建一个新的activity的实例到启动它的任务中。activity可以被多次实例化,每个实例可以属于不同的任务,也可以属于同一个任务。

2)singleTop 

如果一个activity的实例已经存在于当前任务的栈的顶端,系统通过调用它的onNewIntent()方法把intent传到这个实例,而不是创建一个新的实例.如果任务栈存在该activity的实例,但是不位于栈顶或则任务栈中没有activity的实例,则会重新创建新的实例。

例如,假设一个任务的后退栈中有根ActivityAactivityB,C,(A-B-C-D;D位于顶端).一个intent到达了D类型的activity(不是指这里的acitivityD).如果D具有默认的"standard"启动模式,一个新的类的实例被启动并且栈变为A-B-C-D-D.然而,如果D的启动模式是"singleTop",那么这个已存在的ActivityD就通过onNewIntent()接收到intent,因为它在栈的顶端栈于是依然保持A-B-C-D.又然而,如果一个intent到达了B类型的activity(不是此处的activityB),那么一个新的B实例被添加到栈中,即使它的启动模式是"singleTop"。

3)singleTask

a、设置为singleTask的Activity是单例的,即同一时刻系统中只能存在该Activity的一个实例;

b、如果Activity的实例不存在,当该Activity的taskAffinity值与当前task的吸附值相同,则直接在当前task中创建该activity的实例,否则创建新的task,并该activity的实例作为根activity;

c、如果存在该activity的实例,则将任务栈中位于其上的其他Activity销毁。调用onNewIntent方法后,重新启动该实例,而不是创建新实例。

注:尽管activity在一个新任务中启动,后退键依然可以返回到上一个activity。

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

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


4)singleInstance

a、设置为singleInstance的Activity是单例的,即同一时刻系统中只能存在该Activity的一个实例;

b、设置为singleInstance的Activity,不能与其他Activity共存一个task中。当该activity的实例不存在时,在新的任务中创建activity的实例,如果该activity的实例已经存在,则调用onNewIntent方法后,重新启动该实例。

c、通过设置为singleInstance模式的Acitivity启动其他Activity时,被创建的Activity首先寻找与其吸附值相同的任务,如果存在相同的任务,则在该任务中创建实例,否则在新任务中创建实例。


有两个应用程序A和B,B1为应用B的主activity,并且lauchMode为singleTask,当A1->A2->B1时,B1会新建一个任务栈,并且B1位于栈底,此时B1->B2,B2位于B1创建的栈中,此时如果按Back键,会依次返回到A1。但是当按Home键返回到桌面时,长按Home键,会出现刚才创建的两个任务。如果在桌面启动A1,会启动A1所在的任务中,此时A2处于栈顶。如果在桌面启动B,会发现不会创建新的任务,会销毁之前的任务栈中的B2,B1位于栈顶。

2、使用Intent的Flag

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

1)FLAG_ACTIVITY_NEW_TASK 与singleTask有相同的行为。

2)FLAG_ACTIVITY_SINGLE_TOP 与singleTop有相同的行为。

3)FLAG_ACTIVITY_CLEAR_TOP

如果要启动的activity已经在当前任务中运行,那么在它之上的所有其它的activity都被销毁掉,然后这个activity被恢复,而且通过onNewIntent()intent被发送到这个activity(现在位于顶部了)。

3、清空后退栈

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

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

  • alwaysRetainTaskState

      如果任务的根activity的这个属性被设置为"true",前面所述的默认行为就不会发生.任务保持所有的后退栈中的activity,即使经过很长一段时间.这个特性只针对Task的根Activity有意义;对其它Activity来说,忽略之。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。默认值是“false”,一般来说,特定的情形如当用户从Home桌面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。

  • ClearTaskOnLaunch

      用来标记是否从Task中清除除了根activity之外的所有activity。如果任务的根activity的这个属性被设置为"true",在用户离开任务再回来时,栈中是清空到只剩下根activity.换句话说,它是与alwaysRetainTaskState反着来的.用户回到任务时永远见到的是初始状态,即使只离开了一小会.默认值是“false”。假设,从Home界面启动了Activity A,并从那里迁移至Activity B。接下来用户按下HOME,然后返回Activity A。一般,用户可能见到的是Activity B,因为它是A的Task中最后工作的内容。然而,如果A设定这个特性为“true”,当用户按下HOME并使这个Task再次进入前台时,其上的所有的Activity(在这里是B)都将被清除。因此,当返回到这个Task时,用户只能看到A。

  • finishOnTaskLaunch

      这个属性很像clearTaskOnLaunch,但是它作用于一个单独的activity,而不是整个任务.它也可以导致任何activity死亡,包含根activity.当它被置为"true"时,activity只在当前会话中存活.如果用户离开然后回来,它就已经不在了.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值