Tasks And Back Stack

来源:互联网 发布:交友网站程序源码 编辑:程序博客网 时间:2024/05/28 04:52

一个应用通常包含多个Activity。每个activity被设计为以一种指定的动作用户可以去执行另外的另外的Activity。比如一个email应用是一个Activity,显示一个新的邮件列表。当用户选择一个email,新的Activity打开email。

         一个activity可以启动在另外应用中启动的Activity。比如,你的应用想发送一个邮件,你可以定义一个意图是发送的包括数据比如邮件的地址和消息。一个activity从声明中另外的一个应用处理这个意图。在这种情况下,为了发送邮件的意图,所以一个邮件应用构成多个应用,当email被发送,你Activity恢复,并且看起来是email像是你应用的一部分。虽然activity是从不同的应用。Android保持这种无缝的用户体验,同时保持两个Activity在同一个任务里。

         一个任务是一个Activity集合用户和它交互执行一个特定的工作。这些Activity会被安排在一个back Stack里,按顺序在每个activity被打开。

设备的主屏是大多数任务的起点。当用户点击按钮一个应用的启动器,这个应用的任务就到了前端。假如这个任务不存在,就新建一个“main”Activity为这个应用在根Activity在栈中。

 

当当前的Activity开始启动另外时,新的Activity被推送到栈的最顶层并获取焦点。前一个Activity保留在栈中,但是是停止的。当一个Activity停止后,系统保持当前的状态。当用户点击回退按钮时,当前的Activity会被弹出从栈的顶端并且前一个Activity恢复。Activity在栈中不能重新排列,只能弹出和推入栈中,推入Activity当启动当前的Activity并且弹出当用户用回退按钮离开时。这样,这个返回栈操作是一个后进先出的结构。开图一

 

假如你继续按返回键,然后每个Activity都会被弹出显示上一个直到用户返回到主屏。当所有的Activity从栈中被移除,任务也将不存在。

         一个任务是可以被移到背景后的一个内聚单元当开始一个新的任务或者跳到主屏。当在在背景后时,所有在这个任务中的Activity都会被停止,但是返回栈为任务完整的保留,任务只是简单的失去了焦点被另一个任务代替。一个任务可以返回到前景,用户可以选他们的。假如,比如当前的任务A有三个Activity在有两个在当前的Activity下。用户按Home键,然后启动另一个新的应用。当主屏出现,任务A进入后台。当新的应用启动,系统启动一个新的任务B和他自己的栈。在操作应用程序后,用户返回主屏选择启动任务A的应用。现在任务A,现在任务A到了前端,所有三个Activity在完整的在它的栈中并且在栈顶的Activity恢复。在这点上,用户可以从主屏中选择启动任务B。这是一个多任务的例子在android上。

注意:多任务可以同时被后台持有。但是,假如用户运行了太多的任务在同一时间,系统会销毁后台的Activity为了回收内存,引起Activity状态的丢失。

 

因为Activity在返回栈中不能被重新排列,假如你的应用需要用户启动一个特别的Activity超过多个Activity,一个新的实例将会被创建并压入栈中(而不是使用任何上一个以前存在的实例)。同样的,一个Activity在你的应用中多次被实例化。同样的用户用后退键返回导航,每一个实例重新显示并一个个按顺序打开。但是你可以修改这种行为假如你不想一个Activity被多次实例化。怎么做是接下来需要讨论的不部分。

总结默认的行为和任务:

1.      当Activity A启动一个Activity B,Activity A 被停止,但是系统保留了它的状态。假如用户按返回键Activity A会恢复到原来存储的状态。

2.      当你用户按Home键离开一个任务时,当前的Activity被停止并且任务到后台。系统保留每一个Activity在任务中的状态。假如用户从启动按钮中选择恢复任务,这个任务将会到前端并恢复在栈顶的Activity。

3.      假如用户点击返回按钮,当前的activity被弹出栈并销毁。前一个Activity在栈中的恢复。当一个Activity被销毁,系统不再保存它的状态。

4.      Activity可以被多次实例化,即使在另外的任务里。

 

注意导航设计

 

保存Activity的状态

在上面讨论的,系统默认的行为保存Activity的状态当被停止。这种方式当用户导航返回到上一个Activity时,他的界面显示和以前一样。但是你可以应该保留Activity的状态用回调方法。以防止Activity被销毁后被重新创建。

         当系统停止一个你的Activity(比如当一个新的Activity启动或新的任务移动到后台),系统都有可能被完全的销毁当它需要系统内存的时候。当发生这个时,信息关于这个Activity的都会丢失。假如发生时,系统知道这个Activity活动在哪一个栈中,但是当系统重新带这个Activity到栈顶时需啊哟重新创建。为了避免丢失用户的操作,你必须主动的保留它用实现onSaveINstanceState()方法。

 

管理任务

         Android管理任务和栈接下来就描述。各个Activity在同一个栈中启动的顺序并在先进后出的栈中他们很好的为多个应用执行并且你不用担心你的Activity和任务的关联,或者是否存在在回退栈中。然而,你想决定你想打断一般的行为。也许你想一个Activity在你应用中开始一个新的任务里启动(代替当前的任务)。或者你开始一个新的Activity,当你想带一个已经存在的实例(代替一个新的实例在返回栈顶);或者你想清除返回栈所有的除了根Activity当你离开当前任务时。

         你可以做这些在<activity>元素中,或带一个标示在调用startActivity()

在这方面属性有

taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLauch

alyasRetainTaskState

finishOnTaskLaunch

 

并且可以使用的标志有

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_SINGLE_TOP

在接下来的部分中,你可以看到这些清单属性和意图的属性这样如何和任务相关并且在回退栈中的行为。

警告:许多应用不需要打断默认的行为为Activity和任务。假如你决定需要Activity修改默认的行为,用户注意要确认测试在启动时适用的当回退时从另个Activity和任务在按回退键。确定测试导航的行为是否和用户的预期是否冲突。

 

定义启动模式

启动模式允许你定义一个新的实例和当前任务的关联。你可以定义不同的模式通过两种方式。

一个是用清单文件:当你描述一个Activity在你的清单时,启动时你可以指定怎样一个Activity和任务的关系。

用Intent的标志:当你调用startActivity(),你可以包含一个标志位描述一个新的Activity与当前任务的关联。

         通常,一个Activity A启动一个Activity B,Activity B可以定义在它的清单,可以关联当前的任务并且Activity A可以请求怎么样Activity B关联当前的任务。假如每个Activity 定义怎么样一个Activity B必须关联一个任务,让回Activity A的请求(如定义的意图),是荣幸的Activity B的请求(如定义它在清单中)

         注意:一些启动模式在清单中有用但是在Intent中没有用。相同的一下模式在Intent中有用在清单中没有定义。

用清单文件

         当你说明一个activity在你的清单里时,你可以指定activity在和任务的关系,用launchMode属性模式。

         lauchMode属性指定了这样启动一个Activity,这里一共有4种不同的模式。

1.      standard:默认是方式,系统创建一个新的activity在任务中,从它的意图。Activity可以被多次实例化,可以属于多个任务也可以一个任务中多个实例。

2.      singleTop:假如一个Activity的实例在当前最顶,系统按路线发送意图会调用onNewIntent()方法,而不是创建一个新的实例。这个activity可以多次实例化,即使在多个任务中或者在一个任务中也可以实例化多个。(但是只有当activity在返回栈的顶端不是一个已经存在的activity实例)。

比如,假设任务栈中的包含A,B,C,D四个Activity,D在顶端。一个意图启动一个Dactivity,假如是“standard”模式就会创建一个新的实例栈中就变成ABCDD,如果D的模式是“singleTop”,已经存在的D实例会调用onNewIntent,因为它在栈的最顶,栈就变成了ABCD,但是如果一个意图启动一个B,那个即使这个模式为“singleTop”也会增加一个新的实例在栈中。

3.      singleTask:系统创建一个新的任务实例化一个activity在一个新的任务中。然而,假如一个Activity实例已经存在一个独立的任务中,系统按意图启动一个已经存在的实例会调用onNewIntent方法,而不是重新创建一个新的实例。只有一个实例同时存在。

注意:虽然Activity重新启动在一个新的task,但是返回按钮仍然返回上一个Activity

4.      singleInstance:同“singleTask”一样,除了系统不启动另外一个activity在任务中。Activity总是只有一个并且只是任务的成员;任何activity被它启动都会在一个独立的任务。

 

作为另一个例子,andorid浏览器应用表述web浏览器Activity总是会被打开在它自己的任务中,它指定了模式为”singleTask”在你<activity>元素中。这个意思是假如你的应用发送一个意图打开android的浏览器,它的activity不是放置在相同的任务作为你的应用,相反的是一个新的任务启动为浏览器,假如浏览器已经存在在任务中在后台,这个任务就带到前端执行新的意图。无论一个Activity启动在一个新的任务中或者在同一同一个Activity启动它,返回按钮总是可以返回到用户的上一个activity。然而,假如你启动一个指定“singleTask”模式时,这个activity的实例已经存在后台,整个任务被带到前端。在这点上返回栈包含了所有的activity从这个任务中带来,在栈的顶端。

 

         注意:这个行为你指定的登录模式属性可以被覆盖,用意图启动你的Activity,接下来部分会讨论。

使用意图标志

当你启动一个activity,你可以修改默认关联的activity在它的任务中被包含标志在意图你需要发送startActivity方法里。这个标志可以使用修改默认的行为有:

 

         FLAG_ACTIVITY_NEW_TASK:启动一个Activity在一个新的任务。假如任务里已经在运行你要启动的Activity,任务被带到前端带上它最后状态和Activity接收新的意图用onNewInten()。

这种产品行为作为“singleTask”值,讨论和前一部分一样。

         FLAG_ACTIVITY_SINGLE_TOP:假如activity(在返回栈的顶端)被当前的Activity启动,假如已经存在的实例接收到调用onNewIntent(),代替创建一个新的Activity实例。

这个的行为和“singleTop”模式,讨论和上一部分一样。

         FLAG_ACTIVITY_CLEAR_TOP:假如activity被启动在当前的任务中,然后代替一个新的activity,所有另外的在它顶端的都销毁掉,这个意图发送恢复顶端的activity通过调用onNewInten().这里没有相应的

 

注意,假如被指定的Activity启动模式为“standard”,它也会被移走从栈中和一新的实例被启动来处理传入的意图。这是因为一个新的实例创建新的意图启动模式是“standard”

 

执行关系

这里的关系是一个activity属于哪个任务。默认的所有的activity在同一个应用中相互有个关系。所以默认的所有的Activity在相同的应用中最好是在相同的任务中。如果需要改变默认的关系为一个activity。Activity 定义了不同的应用可以分享一个关系,或者activity定义在同一个应用被设计在不同的任务中。

你可以修改关系为在<activity>标签中taskAffinity属性。

 

taskAffinity属性可以填充一个字符串值,必须是唯一的在默认包里清单元素。因为系统用这个名字定义默认的任务关为这个应用。

这个关系发挥的两种作用:

1.      当一个意图启动Activity包含FLAG_ACTIVITY_NEW_TASK标志时。

一个新的activity被默认的启动在这个activity任务中调用startActivity包含FLAG_ACTIVITY_NEW_TASK标志,系统会去寻找不同的任务存储这个新的activity。经常,是一个新的任务。但是,这不是必须的。假如这个已经存在任务同一个关系作为一个新的activity,activity被启动在这个任务中。假如没有就创建一个新的任务。

假如这个标志为引起开始一个新的任务和用户按主界面键离开,这里必须是同一个个方式为用户导航回任务,整个(像通告管理)总是开启一个新的任务在另外的任务中,从来不是他们自己的一部分。所以他们总是设置FLAG_ACTIVITY_NEW_TASK在意图中通过startActivity。假如你有一个Activity可以调用外部的实体用这个标志,注意这个用户有一个独立的方式返回被启动的任务,像一个启动按钮(这个根Activity任务中有个CATEGORY_LAUNCHER过滤器,可以看启动一个任务在下面的部分)

2.      当一个activity有个属性为allowTaskReparenting属性为true.

在这种情况下,activity可以从这个任务移动到一个它相关的任务,当这个任务到前端时。

比如,假设一个activity天气预报的条件选择城市是一个应用的一部分。它有相同的关系作为另外的activity在相同的应用(默认的应用关系)并且允许重新排列。当一个你的activity启动一个天气预报Activity时,它属于你的在同一个任务中作为你的一个Activity。然而,当旅游应用任务到前端时,天气预报任务重新被分配任务并显示。

 

小提示:假如一个apk文件包含多个“application”从用户的角度看,你也许希望taskAffinity属性可以分配给不同的关系到各个activity在每个相关的“application”

 

清理返回栈

假如用户离开一段很长的时间,系统将会清理任务中的所有activity除了根Activity。当用户再次返回任务时,只有根activity被存储了。系统这种行为,因为在长期的大量时间,用户已经放弃他们需要做的并且重新开始一个新的任务。

这些activity属性可以用来改变这些行为。

 

alwaysRetainTaskState:假如这个属性是true在根activity中在一个任务中,刚才描述的默认行为不会发生。任务会一直保留所有的activity在栈中。

clearTaskOnLaunch:这个属性如果是true在根activity中在一个任务中,这个栈会被清理到根activity,无论用户离开任务并返回它。换句话说,它是alwaysRetaniTaskState的相反。这个用户可以返回在它的初始状态,及时离开任务一会会。

finishOnTaskLaunch:这个属性像clearTaskOnLaunch,但是只能在一个activity里使用,不是在整个任务。他可以引起任何activity消失,包括根activity。当它被设置为true,这个activity保留一部分在当前任务中。假如你离开并返回任务,它不在存在。

 

 

启动一个任务

你可以设置一个activity在任务中作为一个入口点在给定的意图过滤器“android.intent.action.MAIN”作为一个特殊的动作并且“android.intent.category.LAUNCHER”作为指定的分类。

一个这种意图过滤器可以引起一个activity被展示在一个应用的启动,给用户一个方式启动Activity并返回一个任务它创建在它启动后。

 

这里第二个重要的是:用户必须离开一个任务并且返回到使用这个activity的启动项。因为这个原因,这里两种模式,标志activity总是初始化一个任务,”singTask”和“singleInstance”,应该当activity有ACTON_MAIN并且CATEGORY_LAUCHER过滤。想象一下,举个例子,当在没有过滤器时。一个意图登录一个“singleTask”activity,初始化一个新的任务,并且用户花时间在这个任务上。用户可以按主屏键。一个任务被发送到后台并不可见。现在用户没有返回这个任务的方法,因为他不代表应用的启动项。

 

这种情况你不用用户返回一个activity可以设置<activity>元素中finishOnTaskLauch为true.