Activity启动模式 Tasks和Back Stack
http://www.cnblogs.com/mengdd/archive/2013/06/13/3134380.html
Task是用户在进行某项工作时需要与之交互的一系列activities的集合。这些activities按照它们被打开的顺序,被安放在一个堆栈里(back stack)。
一个activity甚至可以打开其他应用的activity。
比如你的应用需要发送一个电子邮件,你可以定义一个intent来执行发送动作,intent包含一些必要的数据,然后启动另一个应用中的activity来执行发送邮件的动作,当邮件发送完,又回到你的activity。
Android会将这两个activity放在同一个task中来保持一致的用户体验。
Activity压栈
当前的activity启动一个新的activity时,新的activity会被压在back stack的栈顶并且获得焦点。
前一个activity仍然在栈中,但是stopped。
当一个activity停止时,系统会保持它的用户交互状态。
当用户按下Back键,当前activity会出栈(这个activity会被销毁),前一个activity会被恢复,并且它的UI状态也会被恢复。
当栈中的activities依次弹出,栈空了之后,task就不存在了。
Multitasking:Task在后台
Task也只是一个有凝聚力的单元,当用户开启一个新的task,或者Home键回到桌面时,task将会变为在后台运行。
当Task在后台时,其中所有的activity都是停止的,back stack保持不变,这个task只是失去了焦点。
Task可以回到前台状态,这样用户就可以回到他们离开的现场,即最顶端的activity会resume。
后台中可以保持多个task,但是系统可能会kill后台的activity用来恢复内存,这样就会导致activity的状态丢失。
保存Activity状态
当activity停止时(stopped),系统的默认行为是保存它的状态。
然而,你可以,并且应该使用回调方法主动保留你的状态,以防activity被系统kill而需要重建。
当系统为了恢复内存而kill掉activity时,activity的状态信息会丢失。
但是系统仍然知道这个activity在back stack中的位置,当这个activity返回到栈顶时,系统会重建(recreate)它,而不是像之前一样恢复它(resume)。
所以为了不丢失用户的工作,你需要实现 onSaveInstanceState()
方法来主动地保存数据。
管理Task
Android系统是这样管理task和back stack的:将activity按照启动的顺序压入堆栈中,如果一个activity被启动多次,会创建它的多个实例,然后将新的实例压入栈中。
如果你想介入并更改这种默认的行为也可以。
比如你可能想在你的某一个activity启动时新开启一个task(而不是放在当前task中);
又或者,当你启动一个activity时,你希望把它的现有实例提到前面来(而不是在栈顶创建一个新的实例);
或者,你希望在用户离开你的task时清除除了根activity之外的所有activity。
要做这些事,你可以通过manifest中 <activity>
元素的属性,还可以通过设置 startActivity()
中传递的intent的flag来完成。
你可以使用的 <activity>
的属性:
- taskAffinity
- launchMode
- allowTaskReparenting
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
以及主要的intent的flag:
定义启动模式
启动模式允许你定义一个新的activity实例是如何和当前task关联的。
你可以通过两种方式来定义启动模式:在manifest中定义或者通过用intent的flag。
这里有两点需要注意:
1.有些启动模式只能在manifest中定义,也有一些只能通过intent的flag定义。
2.当一个activity A启动一个activity B时,如果B在它的manifest中定义了启动模式,但是A通过intent要求它用另一种启动模式,以A的要求为主。
使用manifest file定义启动模式
可以在manifest文件中 <activity>
标签下使用 launchMode
属性定义activity和task关联的方式,它规定了activity如何启动并进入一个task。
注意,在manifest中定义的启动模式可以被启动activity的intent中的flag标明的模式覆盖。
有下面几种属性值:
"standard" (the default mode)
默认模式。在当前task中,activity的新实例被创建,并且传递intent给它。一个activity可以被实例化多次,每个实例可以属于不同的task,一个task也可以有多个它的实例。
"singleTop"
如果当前task的顶部已经有一个这个activity的实例,系统就通过 onNewIntent()
方法向这个实例传递intent,而不是重新建立activity的实例。
一个activity可以被实例化多次,并且实例可以属于不同的task,一个task也可以有多个它的实例(顶部的activity不是这个activity的实例时,就会重新实例化)。
"singleTask"
系统将会重新创建一个task并且实例化activity,将其放在task的根部。
然而,如果这个activity的实例已经在一个单独的task中存在,系统将会调用 onNewIntent()
方法将新的intent传递给这个已经存在的实例,而不是重新创建实例。
在任一时刻,只能有一个这个activity的实例存在。
"singleInstance"
和"singleTask"类似,唯一不同的是系统不会在这个activity的实例所在的task中启动任何其他activity。
这个activity的实例永远是这个task中的唯一一个成员,这个activity启动的任何其他activity都将在另外的task中打开。
返回处理
不管activity是在一个新的task启动还是当前task启动,返回键永远把用户带到之前的那个activity。
但是有一种特殊情况:如果你启动一个启动模式为singleTask的activity,如果这个activity在一个后台task存在实例,那么这整个task将会被放到前台,这时候,back stack就会包含这个task中所有的activities,并且它们是放在栈顶。
如下图:
使用Intent的flag标明启动模式
通过设置传递给 startActivity()
的intent的flag,可以修改要启动的activity和它的task的关联模式。
可以使用的flags有:
和之前讨论过的"singleTask"相同,在新的task中启动activity,如果一个你需要的activity的task已经存在,则将它推向前台,恢复其上一个状态,它通过onNewIntent()收到这个新的intent。
和"singleTop"行为相同,如果被启动的activity是当前顶部的activity,则已经存在的实例收到 onNewIntent()
,而不是新建实例。
如果被启动的activity已经在当前task运行,不创建它的新实例,而是销毁在它之上的其他所有activities,然后通过 onNewIntent()
传递一个新的intent给这个恢复了的activity。
这个行为在 launchMode
中没有对应的属性值。
注意,如果activity的启动模式是"standard",它自己也将被移除,然后一个新的实例将被启动。
这是因为当启动模式是"standard"时,为了接收新的intent必须创建新的实例。
处理affinities
Affinity指示了activity更倾向于属于哪个task。
默认情况下,同一个应用的activities倾向于在同一个task中。你可以通过<activity>标签中的 taskAffinity
来修改这种行为。
详细内容请查看:API Guides: Tasks and Back Stack
http://developer.android.com/guide/components/tasks-and-back-stack.html
清理Back stack
如果用户离开一个task很久,系统就会清理这个task中的所有activities,除了根activity。当用户返回到这个task,只有根activity会被恢复。
有一些activity的属性,你可以用来改变这一行为:
如果这个属性在task的根activity中被设置为true,那么上面描述的默认行为不会发生,即便过了很长时间,task仍将会保持所有的activities。
如果这个属性在task的根activity中被设置为true,每次用户离开这个task,整个task都会被清到只剩根activity。
这样用户永远只能返回到它最初的状态,即便离开的时间很短。
这个属性和上一个很像,但是它作用于单个activity,而不是整个task。
它可以引起任何activity离开,包括根activity。
当它被设置为true时,这个activity只在当前会话中属于这个task,如果用户离开再返回,它不会再出现。
开启一个task
你可以通过给activity一个intent filter(action是"android.intent.action.MAIN",category是"android.intent.category.LAUNCHER"),让这个activity是一个task的进入点。
如下:

<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>

一个这样的intent filter会使得这个activity的icon和label显示在程序启动处,提供了一种方法,使得用户可以启动这个activity,当它启动后,用户也可以通过它来返回到这个task。
第二个能力是很重要的:用户必须能够离开一个task,然后通过activity launcher返回到它。
因为这个原因,两个让activity永远实例化一个task的启动模式:"singleTask" 和"singleInstance",应该仅在activity有一个 ACTION_MAIN 和CATEGORY_LAUNCHER filter的时候用它们。
参考资料
API Guides: Tasks and Back Stack
http://developer.android.com/guide/components/tasks-and-back-stack.html
<activity>标签:
http://developer.android.com/guide/topics/manifest/activity-element.html
关于启动模式,还可以参见博文:
http://www.cnblogs.com/fanchangfa/archive/2012/08/25/2657012.html
Activity启动模式 Tasks和Back Stack的更多相关文章
- Activity启动模式 及 Intent Flags 与 栈 的关联分析
http://blog.csdn.net/vipzjyno1/article/details/25463457 Android启动模式Flags栈Task 目录(?)[+] 什么是栈 栈 ...
- 【转】Activity启动模式 及 Intent Flags 与 栈 的关联分析
http://blog.csdn.net/vipzjyno1/article/details/25463457 在学习Android的过程中,Intent是我们最常用Android用于进程内或进 ...
- Android Activity 启动模式详解
最近有群里的朋友问我 Activity的四种启动模式分别是什么意思? 当初因为项目比较忙,草草的解释了下, Api文档中说的也只是一般,在这里就小记一下吧,以便有更多的朋友对Activity启动模式了 ...
- Android中Activity启动模式详解
在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...
- Android-3 Activity启动模式
Activity启动模式 android:launchMode="singleTask" * Standard 每次都创建一个新实例 -- TaskID不变,ActivityID改 ...
- Activity 启动模式 FLAG
原文:https://blog.csdn.net/youhongyan/article/details/64151922 一.Activity启动模式的设置在AndroidManifest.xml文件 ...
- 【转】Android总结篇系列:Activity启动模式(lauchMode)
[转]Android总结篇系列:Activity启动模式(lauchMode) 本来想针对Activity中的启动模式写篇文章的,后来网上发现有人已经总结的相当好了,在此直接引用过来,并加上自己的一些 ...
- Activity启动模式(lauchMode)
Activity启动模式(lauchMode) 本来想针对Activity中的启动模式写篇文章的,后来网上发现有人已经总结的相当好了,在此直接引用过来,并加上自己的一些理解,在此感谢原作者. 文章地址 ...
- AndroidのActivity启动模式
Activity启动模式 .概念 Activity启动模式定义了Activity启动的规则,它决定着Activity的实例创建与重用与否 .属性 Activity的启 ...
随机推荐
- Angularjs 通过asp.net web api认证登录
Angularjs 通过asp.net web api认证登录 Angularjs利用asp.net mvc提供的asp.net identity,membership实现居于数据库的用户名/密码的认 ...
- js中的DOM操作汇总
一.DOM创建 DOM节点(Node)通常对应于一个标签,一个文本,或者一个HTML属性.DOM节点有一个nodeType属性用来表示当前元素的类型,它是一个整数: Element,元素 Attrib ...
- springboot+cloud 学习(二)应用间通信Feign(伪RPC,实则HTTP)
在微服务中,使用什么协议来构建服务体系,一直是个热门话题. 争论的焦点集中在两个候选技术: RPC or Restful Restful架构是基于Http应用层协议的产物,RPC架构是基于TCP传输 ...
- JavaWeb学习(二)———Tomcat服务器学习和使用(一)
一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件是配置的核心文件. 如果想修改Tomcat服务器的启动端口,则可以在server.xml ...
- Java基础之基础语法
前言:Java内功心法之基础语法,看完这篇你向Java大神的路上又迈出了一步(有什么问题或者需要资料可以联系我的扣扣:734999078) 一个Java程序可以认为是一系列对象的集合,而这些对象通过调 ...
- MyBatis从入门到放弃二:传参
前言 我们在mapper.xml写sql,如果都是一个参数,则直接配置parameterType,那实际业务开发过程中多个参数如何处理呢? 从MyBatis API中发现selectOne和selec ...
- java awt学习笔记
最近这两天,花了些时间温习了java.awt的学习,故今日花些时间写下自己的总结吧. 1.常见的组件:Button.TextArea.Label.Checkbox.TextField Containe ...
- Linux中ls命令用法
ls 命令的含义是list显示当前目录中的文件名字.注意不加参数它显示除隐藏文件外的所有文件及目录的名字. 1)ls –a 显示当前目录中的所有文件,包含隐藏文件 命令: aijian.shi@U-a ...
- [转]Angular4 自制分页控件
本文转自:https://blog.csdn.net/Junyuan_123/article/details/79486276 过年后第一波,自制的分页控件,可能功能没有 PrimeNG 那么好,但是 ...
- 【WebSocket No.2】WebSocket和Socket实现聊天群发
介绍: 前面写过一篇简单的websocke实现服务端.这一篇就不在说什么基础的东西主要是来用实例说话,主要是讲一下实现单聊和群组聊天和所有群发的思路设计. 直接不懂的可以看一下上一篇简单版本再来看也行 ...