Activity、Task、Application关系+Intent启动Flag

什么是Android  Application?

简单来说,一个apk文件就是一个Application。

任何一个AndroidApplication基本上是由一些Activities组成,当用户与应用程序交互时其所包含的部分Activities具有紧密的逻辑关系,或者各自独立处理不同的响应。

这些Activities捆绑在一起成为了一个处理特定需求的Application,并且以“.apk”作为后缀名存在于文件系统中。

Android平台默认下的应用程序 例如:Email、Calendar、Browser、Maps、TextMessage、Contacts、Camera和Dialer等都是一个个独立的Apps。

 

安装Application的过程也可以简单理解为将其所包裹的Activities导入到当前的系统中,如果系统中已经存在了相同的Activities,那么将会自动将其关联,而不会重复安装相同的Activities,避免资源的浪费。

Application卸载的过程也会检查当前所关联的Activities是否有被其它Application标签所关联,如果仅仅是提供当前的Application使用,那么将会彻底被移除,相反则不做任何操作。

 

就像我们已经知道的,Application基本上是由四个模块组成:Activity、Service、ContentProvider 和 Broadcast Receiver,其中Activity是实现应用的主体。

 

什么是 Activity Stack?

操作应用程序时,有时需要调用多个Activities来完成需求,例如:发送邮件程序,首先是进入邮件主界面,然后启动一个新的Activity用于填写新邮件内容,同时可以调出联系人列表用于插入收件人信息等等。在这个操作过程中Android平台有一个专门用于管理Activities堆栈的机制,其可以方便的线性记录Activities实例,当完成某个操作时,可以通过导航功能返回之前的Activity(通过按操作台的“Back”按钮)。

每次启动新的Activity都将被添加到Activity Stack。用户可以方便的返回上一个Activity直到HomeScreen,到达HomeScreen后,将无法再继续查看堆栈记录(俗话说:到头了)。如果当前Task被中止(Interrupting thetask),返回到系统主界面后启动了其它操作,当希望返回到前一个Task继续执行时,只需要再次通过主界面的Applicationlauncher或者快捷方式启动这个Task的Root Activity便可返回其中止时的状态继续执行。

相对于Views、Windows、Menus和Dialogs而言,Activity是唯一可被记录在Historystack中的数据,所以当你所设计的应用程序需要用户由A界面进入到次一级界面B,当完成操作后需要再次返回A,那么必须考虑将A看作为Activity,否则将无法从历史堆栈中返回。

 

什么是Task

当我们需要一个Activity可以启动另一个Activity,可能另外一个Activity是定义在不同应用程序中的Activity。

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

对于用户来说,看起来好像是地图浏览与你的Activity一样,属于相同的应用程序,即便是它定义在其它的应用程序里,并运行在那个应用程序的进程里。

Android通过将这两个Activity保存在同一个Task里来体现这一用户体验。简单来说,一个Task就是用户体验上的一个“应用”。 
它将相关的Activity组合在一起,以stack的方式管理(就是前面提到的Activity Stack),这就是Task。

 

在Android平台上可以将task简单的理解为幽多个Activity共同协作完成某项应用,而不管Activity具体属于哪个Application,

通过下图可以更清晰的理解Application、task、Activity三者之间的关系:

image

 

Task 有啥用?

我们用过Android的手机就会知道有下面的场景:

假设我们首先在用IReader在看书,从选书到具体书的阅读界面,这是有好几个Activity。我们每一个点击的Activity都被放在阅读这个Task对应的ActivityStack中了,这可以放我们通过回退键返回每一个前面的Activity。

我们在阅读到一半时,想看看Sina微博,按Home键离开了IReader。

在Sina微博界面也是有多个Activity,我们一步到阅读界面。这时候我们每一个点击的Activity都被放在Sina微博这个Task对应的ActivityStack中了,这可以放我们通过回退键返回每一个前面的Activity。

我们这时候再回到IReader读书界面,原先的状态还是保留的。

显然每一个Task有自己的 Activity Stack。

Task就是这样为了方便人们使用手机而设置的,就像前面提到的场景Task可以跨Application。

 

下面这个图从另外一个角度描述了Application Task Activities的关系

image

 

Task通过Application launcher、Home screen的快捷方式或者 由 “RecentTasks”(长时间按住Home键)最近使用过的Task记录中启动。

当从一个Activity中启动另外一个Activity时,Back键将作用于返回前一个Activity,与此同时新开启的Activity将被添加到Activity Stack中。

有关更详细的可以参看这篇文章:

[译]关于Activity和Task的设计思路和方法 
http://blogold.chinaunix.net/u2/85193/showart_1966109.html 

 

参考资料:

http://skyswim42.egloos.com/3127700

关于Activity和Task的设计思路和方法 
http://blogold.chinaunix.net/u2/85193/showart_1966109.html

Android Task 
http://www.apkbus.com/forum.php?mod=viewthread&tid=146

 

Android四种Activity的加载模式

 

建议首先阅读下面两篇文章,这样才可以更好的理解Activity的加载模式:

  Android的进程,线程模型:
  http://blog.csdn.net/AndroidBluetooth/archive/2011/06/15/6547166.aspx其中对“Android的单线程模型”的描述,明白Activity的一些注意事项。

  Android Application Task Activities的关系 
  http://www.cnblogs.com/ghj1976/archive/2011/04/29/2032412.html 尤其要明白 Task 是啥。

 一个Activty的生命周期

  Activty的生命周期的也就是它所在进程的生命周期。

  每一个活动(Activity)都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一个状态的,这些均由系统来完成。 
  但是当一个活动的状态发生改变的时候,开发者可以通过调用 onXX() 的方法获取到相关的通知信息。

  在实现 Activity 类的时候,通过覆盖( override )这些方法即可在你需要处理的时候来调用。

  • onCreate:当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。 
    onCreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onSaveInstanceState()方法保存的状态信息。
  • onStart :该方法的触发表示所属活动将被展现给用户。
  • onResume :当一个活动和用户发生交互的时候,触发该方法。
  • onPause:当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。
  • onStop :当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop方法。所以保存状态信息是应该在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。
  • onRestart :当处于停止状态的活动需要再次展现给用户的时候,触发该方法。
  • onDestroy :当活动销毁的时候,触发该方法。和 onStop方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。
  • onSaveInstanceState:系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。 
    通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。 

 Activity栈

  上面提到开发者是无法控制Activity的状态的,那Activity的状态又是按照何种逻辑来运作的呢?这就要知道Activity 栈。

  每个Activity的状态是由它在Activity栈(是一个后进先出LIFO,包含所有正在运行Activity的队列)中的位置决定的。

  当一个新的Activity启动时,当前的活动的Activity将会移到Activity栈的顶部。

  如果用户使用后退按钮返回的话,或者前台的Activity结束,在栈上的Activity将会移上来并变为活动状态。如下图所示:

  一个应用程序的优先级是受最高优先级的Activity影响的。当决定某个应用程序是否要终结去释放资源,Android内存管理使用栈来决定基于Activity的应用程序的优先级。

  Activity状态 
  一般认为Activity有以下四种状态:

  活动的:当一个Activity在栈顶,它是可视的、有焦点、可接受用户输入的。Android试图尽最大可能保持它活动状态,杀死其它Activity来确保当前活动Activity有足够的资源可使用。当另外一个Activity被激活,这个将会被暂停。 
  暂停:在很多情况下,你的Activity可视但是它没有焦点,换句话说它被暂停了。有可能原因是一个透明或者非全屏的Activity被激活。 
  当被暂停,一个Activity仍会当成活动状态,只不过是不可以接受用户输入。在极特殊的情况下,Android将会杀死一个暂停的Activity来为活动的Activity提供充足的资源。当一个Activity变为完全隐藏,它将会变成停止。 
  停止:当一个Activity不是可视的,它“停止”了。这个Activity将仍然在内存中保存它所有的状态和会员信息。尽管如此,当其它地方需要内存时,它将是最有可能被释放资源的。当一个Activity停止后,一个很重要的步骤是要保存数据和当前UI状态。一旦一个Activity退出或关闭了,它将变为待用状态。 
  待用:在一个Activity被杀死后和被装在前,它是待用状态的。待用Acitivity被移除Activity栈,并且需要在显示和可用之前重新启动它。

 activity的四种加载模式

  在android的多activity开发中,activity之间的跳转可能需要有多种方式,有时是普通的生成一个新实例,有时希望跳转到原来某个activity实例,而不是生成大量的重复的activity。加载模式便是决定以哪种方式启动一个跳转到原来某个Activity实例。

  在android里,有4种activity的启动模式,分别为:

  • standard: 标准模式,一调用startActivity()方法就会产生一个新的实例。
  • singleTop:如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。
  • singleTask: 会在一个新的task中产生这个实例,以后每次调用都会使用这个,不会去产生新的实例了。
  • singleInstance:这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。

  这些启动模式可以在功能清单文件AndroidManifest.xml中进行设置,中的launchMode属性。

  相关的代码中也有一些标志可以使用,比如我们想只启用一个实例,则可以使用Intent.FLAG_ACTIVITY_REORDER_TO_FRONT标志,这个标志表示:如果这个activity已经启动了,就不产生新的activity,而只是把这个activity实例加到栈顶来就可以了。

Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);  intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);  startActivity(intent);  

  Activity的加载模式受启动Activity的Intent对象中设置的Flag和manifest文件中Activity的元素的特性值交互控制。

  下面是影响加载模式的一些特性

  核心的Intent Flag有: 
  FLAG_ACTIVITY_NEW_TASK 
  FLAG_ACTIVITY_CLEAR_TOP 
  FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
  FLAG_ACTIVITY_SINGLE_TOP 
  核心的特性有: 
  taskAffinity 
  launchMode 
  allowTaskReparenting 
  clearTaskOnLaunch 
  alwaysRetainTaskState 
  finishOnTaskLaunch

四种加载模式的区别

 所属task的区别

  一般情况下,“standard”和”singleTop”的activity的目标task,和收到的Intent的发送者在同一个task内,就相当于谁调用它,它就跟谁在同一个Task中。

  除非Intent包括参数FLAG_ACTIVITY_NEW_TASK。如果提供了FLAG_ACTIVITY_NEW_TASK参数,会启动到别的task里。 
  “singleTask”和”singleInstance”总是把要启动的activity作为一个task的根元素,他们不会被启动到一个其他task里。

 是否允许多个实例

  “standard”和”singleTop”可以被实例化多次,并且是可以存在于不同的task中;这种实例化时一个task可以包括一个activity的多个实例; 
  “singleTask”和”singleInstance”则限制只生成一个实例,并且是task的根元素。 
  singleTop要求如果创建intent的时候栈顶已经有要创建的Activity的实例,则将intent发送给该实例,而不创建新的实例。

 是否允许其它activity存在于本task内

  “singleInstance”独占一个task,其它activity不能存在那个task里;

  如果它启动了一个新的activity,不管新的activity的launch mode如何,新的activity都将会到别的task里运行(如同加了FLAG_ACTIVITY_NEW_TASK参数)。 
  而另外三种模式,则可以和其它activity共存。

 是否每次都生成新实例

  “standard”对于每一个启动Intent都会生成一个activity的新实例; 
  “singleTop”的activity如果在task的栈顶的话,则不生成新的该activity的实例,直接使用栈顶的实例,否则,生成该activity的实例。

  比如:

  现在task栈元素为A-B-C-D(D在栈顶),这时候给D发一个启动intent,如果D是“standard”的,则生成D的一个新实例,栈变为A-B-C-D-D。 
  如果D是singleTop的话,则不会生产D的新实例,栈状态仍为A-B-C-D 
  如果这时候给B发Intent的话,不管B的launchmode是”standard” 还是 “singleTop”,都会生成B的新实例,栈状态变为A-B-C-D-B。

  “singleInstance”是其所在栈的唯一activity,它会每次都被重用。

  “singleTask” 如果在栈顶,则接受intent,否则,该intent会被丢弃,但是该task仍会回到前台。当已经存在的activity实例处理新的intent时候,会调用onNewIntent()方法,如果收到intent生成一个activity实例,那么用户可以通过back键回到上一个状态;如果是已经存在的一个activity来处理这个intent的话,用户不能通过按back键返回到这之前的状态。

 

原文地址:http://kb.cnblogs.com/page/99664/

 

  参考资料

  Android的七巧板Activity之一 Activity的生命周期 
  http://winuxxan.blog.51cto.com/2779763/502523

  Android的七巧板Activity之二 Activity的加载模式 
  http://winuxxan.blog.51cto.com/2779763/504047

  Android Activity生命周期 
  http://www.haoni.org/2011/02/25/androidactivityshengmingzhouqi/

  android中activity的四种加载模式 
  http://blog.csdn.net/pcwings/archive/2010/09/19/5895197.aspx

  区分Activity的四种加载模式 
  http://marshal.easymorse.com/archives/2950

  Hello Android 第三版 (二) 
  http://blog.csdn.net/cqwty/archive/2010/09/08/5870219.aspx

  只生成一个Activity的实例 
  http://www.eoeandroid.com/home-space-uid-43043-do-blog-id-6.html

  activity的启动方式(launch mode) 
  http://liubin.nanshapo.com/2010/12/23/activity-launch-mode/

  Android应用程序模型:应用程序,任务,进程和线程 
  http://blog.csdn.net/iefreer/archive/2009/08/18/4460196.aspx

 

关于activity的四种加载模式,我结合网上牛人的例子,android开发指南以及自己的测试写成一篇文档,编码格式utf-8。

下载地址:http://download.csdn.net/source/3368975

----------------------------------------------------------

Intent启动flag

FLAG_ACTIVITY_BROUGHT_TO_FRONT     

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

 

FLAG_ACTIVITY_CLEAR_TOP    

  如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。     例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向ActivityB的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。     上例中正在运行的ActivityB既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为“multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。     这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从NotificationManager处启动一个Activity。

 

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET    

  如果设置,这将在Task的Activitystack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个Activity和它之上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。     这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面选择e-mailapp,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的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中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个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通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。

 

FLAG_ACTIVITY_PREVIOUS_IS_TOP     

   If set and this intent is being used to launch a new activityfrom an existing one, the current activity will not be counted asthe top activity for deciding whether the new intent should bedelivered to the top instead of starting a new one. The previousactivity will be used as the top, with the assumption being thatthe current activity will finish itself immediately.

 

FLAG_ACTIVITY_REORDER_TO_FRONT    

  如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端。     例如,假设一个Task由四个Activity组成:A,B,C,D。如果D调用startActivity()来启动ActivityB,那么,B会移动到历史stack的顶端,现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话,那么这个标志将被忽略。

 

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

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

 

FLAG_ACTIVITY_SINGLE_TOP     

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值