电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

Task和Activity相关(zz)


发布日期:2024/4/8
 

android:allowTaskReparenting

用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)——true表示能移动false表示它必须呆在启动时呆在的那个Task里

如果这个特性没有被设定设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上默认值为false

一般来说当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里由于启动模式为singleTasksingleInstance的Activity只能位于Task的底部因此重新宿主只能限于standardsingleTop模式

android:alwaysRetainTaskState

用来标记Activity所在的Task的状态是否总是由系统来保持——true表示总是false表示在某种情形下允许系统恢复Task到它的初始化状态默认值是false这个特性只针对Task的根Activity有意义对其它Activity来说忽略之

一般来说特定的情形如当用户从主画面重新选择这个Task时系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)典型的情况当用户有一段时间没有访问这个Task时也会这么做例如分钟

然而当这个特性设为true用户总是能回到这个Task的最新状态无论他们是如何启动的这非常有用例如像Browser应用程序这里有很多的状态(例如多个打开的Tab)用户不想丢失这些状态

android:clearTaskOnLaunch

用来标记是否从Task中清除所有的Activity除了根Activity外(每当从主画面重新启动时)——true表示总是清除至它的根Activityfalse表示不默认值是false这个特性只对启动一个新的Task的Activity(根Activity)有意义对Task中其它的Activity忽略

当这个值为true每次用户重新启动这个Task时都会进入到它的根Activity中不管这个Task最后在做些什么也不管用户是使用BACK还是HOME离开的当这个值为false可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task的Activity但不总是

假设某人从主画面启动了Activity P并从那里迁移至Activity Q接下来用户按下HOME然后返回Activity P一般用户可能见到的是Activity Q因为它是P的Task中最后工作的内容然而如果P设定这个特性为true当用户按下HOME并使这个Task再次进入前台时其上的所有的Activity(在这里是Q)都将被清除因此当返回到这个Task时用户只能看到P

如果这个特性和allowTaskReparenting都设定为true那些能重新宿主的Activity会移动到共享affinity的Task中剩下的Activity都将被抛弃如上所述

android:finishOnTaskLaunch

用来标记当用户再次启动它的Task(在主画面选择这个Task)时已经存在的Activity实例是否要关闭(结束)——true表示应该关闭false表示不关闭默认值是false

如果这个特性和allowTaskReparenting都设定为true这个特性胜出Activity的affinity忽略这个Activity不会重新宿主但是会销毁

android:launchMode

用于指示Activity如何启动这里有四种模式与Intent对象中的Activity Flags(FLAG_ACTIVITY_*变量)共同作用来决定Activity如何启动来处理Intent它们是

standard

singleTop

singleTask

singleInstance

默认模式是standard

这些模式可以分成两大组别standardsingleTop一组singleTasksingleInstance一组具有standardsingleTop启动模式的Activity可以实例化很多次这些实例可以属于任何Task并且可以位于Activity stack的任何位置典型的情况是它们会进入调用startActivity()的Task(除非Intent对象包含FLAG_ACTIVITY_NEW_TASK标志在这种情况下会选择一个不同的Task——参考taskAffinity特性)

相反的singleTasksingleInstance只能启动一个Task它们总是位于Activity stack的底部甚至设备一次只能拥有一个Activity的实例——只有一个这样的Task

standardsingleTop模式只在一种情况下有差别每次有一个新的启动standardActivity的Intent就会创建一个新的实例来响应这个Intent每个实例处理一个Intent相似的一个singleTop的Activity实例也有可能被创建来处理新的Intent然而如果目标Task已经有一个存在的实例并且位于stack的顶部那么这个实例就会接收到这个新的Intent(调用onNewIntent())不会创建新的实例在其他情况下——例如如果存在的singleTop的Activity实例在目标Task中但不是在stack的顶部或者它在一个stack的顶部但不是在目标Task中——新的实例都会被创建并压入stack中

singleTasksingleInstance模式也只在一种情况下有差别singleTaskActivity允许其它Activity成为它的Task的部分它位于Activity stack的底部其它Activity(必须是standardsingleTopActivity)可以启动加入到相同的Task中singleInstanceActivity换句话说不允许其它Activity成为它的Task的部分它是Task中的唯一Activity如果它启动其它的Activity这个Activity会被放置到另一个task中——好像Intent中包含了FLAG_ACTIVITY_NEW_TASK标志

android:noHistory

用于标记当用户从Activity上离开并且它在屏幕上不再可见时Activity是否从Activity stack中清除并结束(调用finish()方法)——true表示它应该关闭false表示不需要默认值是false

true值意味着Activity不会留下历史痕迹因为它不会在Activity stack的Task中保留因此用户不能返回它

android:taskAffinity

Activity为Task拥有的一个affinity拥有相同的affinity的Activity理论上属于相同的Task(在用户的角度是相同的应用程序Task的affinity是由它的根Activity决定的

affinity决定两件事情——Activity重新宿主的Task(参考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK标志启动的Activity宿主的Task

默认情况一个应用程序中的所有Activity都拥有相同的affinity捏可以设定这个特性来重组它们甚至可以把不同应用程序中定义的Activity放置到相同的Task中为了明确Activity不宿主特定的Task设定该特性为空的字符串

如果这个特性没有设置Activity将从应用程序的设定那里继承下来(参考<application>元素的taskAffinity特性)应用程序默认的affinity的名字是<manifest>元素中设定的package名

FLAG_ACTIVITY_BROUGHT_TO_FRONT

这个标志一般不是由程序代码设置的如在launchMode中设置singleTask模式时系统帮你设定

FLAG_ACTIVITY_CLEAR_TOP

如果设置并且这个Activity已经在当前的Task中运行因此不再是重新启动一个这个Activity的实例而是在这个Activity上方的所有Activity都将关闭然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中

例如假设一个Task中包含这些ActivityABCD如果D调用了startActivity()并且包含一个指向Activity B的Intent那么C和D都将结束然后B接收到这个Intent因此目前stack的状况是AB

上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent也可以把自己关闭然后重新启动来接收这个Intent如果它的启动模式声明为multiple(默认值)并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志那么它将关闭然后重新创建对于其它的启动模式或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志都将把这个Intent投递到当前这个实例的onNewIntent()中

这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用用于启动一个Task中的根Activity它会把那个Task中任何运行的实例带入前台然后清除它直到根Activity这非常有用例如当从Notification Manager处启动一个Activity

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET

如果设置这将在Task的Activity stack中设置一个还原点当Task恢复时需要清理Activity也就是说下一次Task带着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它)这个Activity和它之上的都将关闭以至于用户不能再返回到它们但是可以回到之前的Activity

这在你的程序有分割点的时候很有用例如一个email应用程序可能有一个操作是查看一个附件需要启动图片浏览Activity来显示这个Activity应该作为email应用程序Task的一部分因为这是用户在这个Task中触发的操作然而当用户离开这个Task然后从主画面选择email app我们可能希望回到查看的会话中但不是查看图片附件因为这让人困惑通过在启动图片浏览时设定这个标志浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

如果设置新的Activity不会在最近启动的Activity的列表中保存

FLAG_ACTIVITY_FORWARD_RESULT

如果设置并且这个Intent用于从一个存在的Activity启动一个新的Activity那么这个作为答复目标的Activity将会传到这个新的Activity中这种方式下新的Activity可以调用setResult(int)并且这个结果值将发送给那个作为答复目标的Activity

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

这个标志一般不由应用程序代码设置如果这个Activity是从历史记录里启动的(常按HOME键)那么系统会帮你设定

FLAG_ACTIVITY_MULTIPLE_TASK

不要使用这个标志除非你自己实现了应用程序启动器与FLAG_ACTIVITY_NEW_TASK结合起来使用可以禁用把已存的Task送入前台的行为当设置时新的Task总是会启动来处理Intent而不管这是是否已经有一个Task可以处理相同的事情

由于默认的系统不包含图形Task管理功能因此你不应该使用这个标志除非你提供给用户一种方式可以返回到已经启动的Task

如果FLAG_ACTIVITY_NEW_TASK标志没有设置这个标志被忽略

FLAG_ACTIVITY_NEW_TASK

如果设置这个Activity会成为历史stack中一个新Task的开始一个Task(从启动它的Activity到下一个Task中的Activity)定义了用户可以迁移的Activity原子组Task可以移动到前台和后台在某个特定Task中的所有Activity总是保持相同的次序

这个标志一般用于呈现启动类型的行为它们提供用户一系列可以单独完成的事情与启动它们的Activity完全无关

使用这个标志如果正在启动的Activity的Task已经在运行的话那么新的Activity将不会启动代替的当前Task会简单的移入前台参考FLAG_ACTIVITY_MULTIPLE_TASK标志可以禁用这一行为

这个标志不能用于调用方对已经启动的Activity请求结果

FLAG_ACTIVITY_NO_ANIMATION

如果在Intent中设置并传递给ContextstartActivity()的话这个标志将阻止系统进入下一个Activity时应用Acitivity迁移动画这并不意味着动画将永不运行——如果另一个Activity在启动显示之前没有指定这个标志那么动画将被应用这个标志可以很好的用于执行一连串的操作而动画被看作是更高一级的事件的驱动

FLAG_ACTIVITY_NO_HISTORY

如果设置新的Activity将不再历史stack中保留用户一离开它这个Activity就关闭了这也可以通过设置noHistory特性

FLAG_ACTIVITY_NO_USER_ACTION

如果设置作为新启动的Activity进入前台时这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()

典型的一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台这个回调在Activity的生命周期中标记一个合适的点并关闭一些Notification

如果一个Activity通过非用户驱动的事件如来电或闹钟启动的这个标志也应该传递给ContextstartActivity保证暂停的Activity不认为用户已经知晓其Notification

FLAG_ACTIVITY_PREVIOUS_IS_TOP

If set and this intent is being used to launch a new activity from an existing one the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one The previous activity will be used as the top with the assumption being that the current activity will finish itself immediately

FLAG_ACTIVITY_REORDER_TO_FRONT

如果在Intent中设置并传递给ContextstartActivity()这个标志将引发已经运行的Activity移动到历史stack的顶端

例如假设一个Task由四个Activity组成ABCD如果D调用startActivity()来启动Activity B那么B会移动到历史stack的顶端现在的次序变成ACDB如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话那么这个标志将被忽略

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

If set and this activity is either being started in a new task or bringing to the top an existing task then it will be launched as the front door of the task This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it) or simply resetting that task to its initial state if needed

FLAG_ACTIVITY_SINGLE_TOP

如果设置当这个Activity位于历史stack的顶端运行时不再启动一个新的

Activity和Task

之前提到的一个Activity可以启动另一个即便是定义在不同应用程序中的Activity例如假设你想让用户显示一些地方的街景而这里已经有一个Activity可以做到这一点因此你的Activity所需要做的只是在Intent对象中添加必要的信息并传递给startActivity()地图浏览将会显示你的地图当用户按下BACK键你的Activity会再次出现在屏幕上

对于用户来说看起来好像是地图浏览与你的Activity一样属于相同的应用程序即便是它定义在其它的应用程序里并运行在那个应用程序的进程里Android通过将这两个Activity保存在同一个Task里来体现这一用户体验简单来说一个Task就是用户体验上的一个应用它将相关的Activity组合在一起以stack的方式管理stack中根Activity启动Task——典型的它就是用户在应用程序启动栏中选择的Activity位于stack顶端的Activity是当前正在运行的——能够聚焦用户的动作当一个Activity启动另一个新的Activity进入stack它成为正在运行的Activity之前的Activity仍保留在stack中当用户按下BACK键当前的Activity从stack中退出之前的那个成为正在运行的Activity

stack包含对象因此如果一个Task中有多个同一个Activity的实例时——多个地图浏览例如——stack为每个实例拥有一个独立的入口位于stack中的Activity不会重新调整只是进入和退出

一个Task就是一组Activity不是一个类或者在manifest中定义的一个元素因此没有办法为Task设置独立于它的Activity的属性值Task的值作为整体在根Activity中设置例如下一个章节会讨论Task的affinity那个值就是从Task中的根Activity中读取的

Task中的所有Activity作为一个单元一起移动整个Task(整个Activity stack)可以进入前台或者退到后台例如假设当前Task中的stack中有个Activity——个位于当前Activity下方用户按下HOME键进入到应用程序启动栏然后选择一个新的应用程序(实际上一个新的Task)当前Task退到后台并且新Task中的根Activity会显示出来然后经过一段时间后用户回到Home画面然后再次选择前一个应用程序(前一个Task)那个拥有个Activity的Task会进入前台当用户按下BACK键屏幕不会显示用户刚刚离开的Activity(前一个Task的根Activity)而是这个stack中的顶端Activity移除相同Task中的前一个Activity会显示出来

刚才描述的行为是Activity和Task的默认行为但有方法来完全改变它Task之间的关联和一个Task中的一个Activity行为受启动Activity的Intent对象中设置的Flag和manifest文件中Activity的<activity>元素的特性值交互控制调用者和响应者都有权决定如何发生

核心的Intent Flag有

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

FLAG_ACTIVITY_SINGLE_TOP

核心的<activity>特性有

taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch

接下来的章节将描述一些Flag和特性的用法如何相互影响以及在使用时的建议

Affinity和新Task

默认情况下一个应用程序中的所有Activity都有affinity——也就是说属于同一个Task中所有Activity有一个设定然而每个Activity都可以在<activity>元素的taskAffinity特性上设置单独的值定义在不同应用程序中的Activity可以共享同一个affinity或者定义在同一个应用程序中的Activity设置不同的affinityAffinity在两种环境下工作Intent对象包含FLAG_ACTIVITY_NEW_TASK标志和Activity的allowTaskReparenting特性设置为true

FLAG_ACTIVITY_NEW_TASK:

之前描述的一个Activity一般通过调用startActivity()启动并加入到Task中它同调用者一样进入同一个Task然而如果传递给startActivity()的Intent对象中包含FLAG_ACTIVITY_NEW_TASK时系统会搜索一个新的Task来容纳新的Activity通常如标志的名字所示是一个新的Task然而并不是必须是如果已经存在一个Task与新Activity的affinity相同这个Activity就会加入到那个Task中如果不是启动一个新的Task

allowTaskReparenting

如果一个Activity的allowTaskReparenting特性设置为true它就能从启动的Task中移到有着相同affinity的Task(这个Task进入到前台的时候)例如在一个旅游的程序中定义了一个可以报告选择城市的天气情况的Activity它和同一个应用程序的其它Activity一样有着相同的Affinity(默认的Affinity)并且它允许重新宿主你的Activity中的一个启动了天气预报因此它初始化到和你Activity相同的Task中然而当旅游应用程序下一次进入到前台时天气预报那个Activity将会重新编排并在那个Task中显示

如果从用户的角度出发一个apk文件包含多个应用的话你可能希望为关联的Activity设置不同的affinity

Launch Mode

这里种不同的启动模式可以设置到<activity>元素的launchMode特性上

standard(默认模式)

singleTop

singleTask

singleInstance

这些模式有以下四点区别

l 哪个Task将容纳响应Intent的Activity对于standardsingleTop来说是产生Intent的那个Task(并调用startActivity())——除非Intent对象包含FLAG_ACTIVITY_NEW_TASK在那种情况下不同的Task将被选择Affinity和新Task中描述的那样对比而言singleTasksingleInstance指示Activity总是一个Task的根它们定义一个Task它们不会加入到另一个Task中

l 是否有多个Activity的实例standardsingleTop可以实例化多次它们可以属于多个Task一个特定的Task可以有相同Activity的多个实例对比而言singleTasksingleInstance只能有一个实例因为这些Activity只能位于Task的底部这一限制意味着在设备的某个时间不会出现这样Task的多个实例

l 是否可以在同一个Task中拥有其它的ActivitysingleInstanceActivity保持单身在它的Task中它是仅有的Activity如果它启动另一个Activity那个Activity将会放入到不同的Task中而不管它的启动模式——好像FLAG_ACTIVITY_NEW_TASK在Intent中一样对于其它方面singleInstance等同于singleTask其它三个模式允许多个Activity加入到这个Task中singleTaskActivity总是位于Task的底部但它可以启动其它的Activity并放入到它的Task中standardsingleTop的Activity可以出现在stack的任何地方

l 是否一个新的实例启动来处理新的Intent对于默认的standard来说都是创建一个新的实例来响应新的Intent每个实例处理一个Intent对于singleTop来说如果它位于目标Task的顶端那么已经存在的实例就可以重复使用来处理这个新的Intent如果它不在顶端那么它就不能重复使用替代的新的实例将创建来响应新的Intent并进入到stack中

例如假设一个Task的Activity stack中包含根Activity A和其它Activity BCD并且D位于顶端因此stack是ABCD有一个Intent来了它要启动D类型的Activity如果D有默认的standard启动模式那么一个新的实例将被启动并且stack变成ABCDD然而如果D的启动模式singleTop已经存在的实例将去处理新来的Intent(因为它正好处在stack的顶端)并且stack依旧是ABCD

换句话说如果来临的Intent是沖着B类型的那么B类型的实例将被创建启动而不管B的模式是standardsingleTop(因为B不处在stack的顶端)因此stack将会是ABCDB

之前提到的设备上不会出现超过一个实例的singleTasksingleInstanceActivity因此那个实例都将去处理所有新来的IntentsingleInstanceActivity总是位于stack的顶端(因为它是task中唯一的Activity)因此它总是处于能处理Intent的位置然而singleTaskActivity可能有或没有其它Activity处于它的上方如果有它就不处于能处理Intent的位置那么这个Intent将被丢弃(即使Intent被丢弃了它的到来会引发那个Task进入到前台在那里它会继续保留

当一个存在的Activity请求去处理一个新的Intent时Intent对象将传到该Activity的onNewIntent()的方法中(原来启动Activity的Intent对象可以通过调用getIntent()得到

注意当一个新的实例创建来处理新的Intent时用户可以按下BACK键返回到之前的状态(前一个Activity)但一个存在的实例来处理新的Intent时用户不能按下BACK键返回到新Intent到来之前的状态

清除stack

如果用户离开Task很长一段时间系统会清除Task中的所有Activity除根Activity外当用户再次返回到这个Task时和用户离开时一样仅仅只是初始化Activity呈现这样做的意图是经过一些时间后用户可能已经忘记之前正在做的事情并且打算回到Task开始些新的时期

这是默认情况这里有一些Activity特性可以用于控制这一行为并且修改它

alwaysRetainTaskState

如果Task的根Activity的这个特性设置为true上面描述的默认行为不会发生Task保留所有的Activity即便是经过很长一段时间

clearTaskOnLaunch

如果Task的根Activity的这个特性设置为true当用户离开Task并返回时stack会清除直到根Activity换句话说它是alwaysRetainTaskState的另一个极端用户总是回到Task的初始化状态即便是一个短暂的离开

finishOnTaskLaunch

这个特性和clearTaskOnLaunch相似但它针对单个Activity不是整个Task它能使任何Activity消失包括根Activity当它设置为true这个Activity仅在当前会话期间保持为Task的部分如果用户离开并再次返回到这个Task它就不再显示了

这里还有其它的方式可以强制Activity从stack中移除如果Intent对象中包含FLAG_ACTIVITY_CLEAR_TOP标志并且目标Task中已经有一个这个类型Activity的实例而且这个实例应该处理这个Intent那么位于其上的Activity都将移除这样这个Activity就能在stack的顶端并响应这个Intent如果这个Activity的启动模式设定为standard它也会从stack中清除然后新的实例启动来响应这个Intent这是因为当启动模式设定为standard总是会创建一个新的实例来响应新的Intent

FLAG_ACTIVITY_CLEAR_TOP经常与FLAG_ACTIVITY_NEW_TASK结合起来使用当一起使用时这些标志可以定位其它Task中已经存在的Activity并且把它置于可以响应Intent的位置

启动Task

如果一个Activity的Intent Filter的action为androidintentactionMAINcategory为androidintentcategoryLAUNCHER它就可以作为一个Task的入口点有这种类型的Filter会在导致这个Activity在应用程序启动栏显示一个图标和标签给用户提供一个方式可以启动这个Task和在任何时候可以再次回到这个Task

第二个能力很重要用户一定可以离开一个Task然后可以再次回到它基于这个原因两个启动模式singleTasksingleInstance应该只在有MAIN和LAUNCHER的Activity上使用例如假设这个Filter没有的话一个Intent启动了一个singleTaskActivity初始化一个新的Task然后用户花费了一些时间在它上面然后用户按下HOME键现在这个Task处于后台并且被HOME画面遮盖由于它不能在应用程序启动栏显示用户就没有办法可以返回它

在面对FLAG_ACTIVITY_NEW_TASK时也有相似的困难如果这个标志导致一个Activity启动了一个新的Task并且用户按下HOME键离开它这里必须有方法可以再次回到它一些机能(如Notification Manager)总是在外部的Task中启动Activity而不是作为自己的一部分因此它总是把FLAG_ACTIVITY_NEW_TASK标志放入Intent然后传递给startActivity()如果你的Activity可能会被外部的机能(可能使用这个标志)调用注意用户可以额外的方式可以返回到启动的Task

如果你不想用户回到某个Activity可以把<activity>元素的finishOnTaskLaunch设置为true

上一篇:过渡很平滑的InfiniteMenus

下一篇:进入Harmony 世界,类库开发最佳实践