//如下Activity中,launchmode如其名: HomeActivity -->
// StandardActivity -->
// singleTaskActivity -->
// singleInstanceActivity -->
// standardActivity -->
// CameraActivity(调用系统相机方法)
// adb shell dumpsys activity
Stack #1:
Task id #5
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.HomeActivity }
Hist #4: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.android.camera/.CameraActivity }
ProcessRecord{d91c03e 25810:com.android.camera/u0a81}
Hist #3: ActivityRecord{e341be0 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Intent { flg=0x10400000 cmp=com.e_gavin163.listest/.task_test.StandardActity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #2: ActivityRecord{faf6cf1 u0 com.e_gavin163.listest/.task_test.SingleTaskActivity t5}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleTaskActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #1: ActivityRecord{a4a7fb9 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Intent { cmp=com.e_gavin163.listest/.task_test.StandardActity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #0: ActivityRecord{9e21af3 u0 com.e_gavin163.listest/.task_test.HomeActivity t5}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.HomeActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Task id #6
TaskRecord{db084a9 #6 A=com.e_gavin163.listest U=0 sz=1}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleInstanceActivity }
Hist #0: ActivityRecord{fac5462 u0 com.e_gavin163.listest/.task_test.SingleInstanceActivity t6}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleInstanceActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Running activities (most recent first):
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Run #5: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Run #4: ActivityRecord{e341be0 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
TaskRecord{db084a9 #6 A=com.e_gavin163.listest U=0 sz=1}
Run #3: ActivityRecord{fac5462 u0 com.e_gavin163.listest/.task_test.SingleInstanceActivity t6}
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Run #2: ActivityRecord{faf6cf1 u0 com.e_gavin163.listest/.task_test.SingleTaskActivity t5}
Run #1: ActivityRecord{a4a7fb9 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Run #0: ActivityRecord{9e21af3 u0 com.e_gavin163.listest/.task_test.HomeActivity t5}
mResumedActivity: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Stack #0:
.
.
.
个人总结:
- 一个应用程序只有一个任务栈
(Stack)
; - 一个应用程序可以有多个
Task
(一个Task
表现于回退栈,按返回键可以推出最上面的Activity
) - 只有
SingleInstance
会新建一个Task
,而不在当前回退栈里面;在SingleInstance
模式的Activity
里面startActivity
,新建的Activity
的TaskID
也是之前主Task
的ID
,而不会是SingleInstance
的TaskID
,SingleInstance
独占一个TaskID
. - 在当前
Activity
中调用其他应用的ActivityB
,ActivityB
会添加到当前应用程序的栈中,并且和当前Activity
同TaskID
(AcitivytB
的launchMode
不为SingleInstance
情况下)。但是不同process
,ActivityB
只会跑在自己的process
中。
以下内容转自franksunny
很想弄清楚启动一个Activity
和Task
(任务)的关系,网上也有很多相关资料,由从源码来具体分析的,也有针对launchmode
来分析,但都不是自己的,理解起来总不是那么容易,为此,尝试着自己去理解其中的逻辑。不过事先需要弄清楚两个问题:
谁负责管理Activity?
Android
的framework
框架中采用C/S
的方式实现由后台服务ActivityManagerService
(很多书上将其简称为Ams
)来管理具体的Acitivity
实例,虽然Ams
命名为ActivityManagerService
,但是它其实不仅仅管理Activity
,他还管理除Acitvity
外的其它三大组件,还包括Intent
、pendingintent
、apk
进程和task
等等,具体可以查看源码frameworks\base\services\java\com\android\server\am
下面的Ams
源码和相关的*Record
类。
网上资料显示在2.3以后的SDK中,Ams
将原来的HistoryRecord
类重新命名为ActivityRecord
类,并将其原来Ams
中的一些处理抽出来成为一个ActivityStack
类,每一个Activity
实例对应一个ActivityRecord
对象,并存放在ActivityStack
中,手机一旦启动,就会启动一个Ams服务,在Ams
服务中有一个ActivityStack
实例专门管理手机上的ActivityRecord
实例。这样一来,不具体分析源码,仅从架构角度来说谁负责管理Activity的问题就清晰多了。
Task到底是什么?
根据对上面问题的解答,既然Activity
是由Ams
通过ActivityStack
来管理的,那么这个Task
又是干什么的呢?
以往基于应用(application)
的程序开发中,程序具有明确的边界,一个程序就是一个应用,一个应用为了实现功能可以采用开辟新线程甚至新进程来辅助,但是应用与应用之间不能复用资源和功能。而Android
引入了基于组件开发的软件架构,虽然我们开发android
程序,仍然使用一个apk
工程一个Application
的开发形式,但是对于Aplication的开发就用到了Activity
、service
等四大组件,其中的每一个组件,都是可以被跨应用复用的哦,这个就是android
的神奇之处。
另外值得一提的是,虽然组件可以跨应用被调用,但是一个组件所在的进程必须是在组件所在的Aplication
进程中。由于android
强化了组件概念,弱化了Aplication
的概念,所以在android
程序开发中,A应用的A组件想要使用拍照或录像的功能就可以不用去针对Camera
类进行开发,直接调用系统自带的摄像头应用(称其B应用)中的组件(称其B组件)就可以了,但是这就引发了一个新问题,A组件跑在A应用中,B组件跑在B应用中,自然都不在同一个进程中,那么从B组件中返回的时候,如何实现正确返回到A组件呢?Task
就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。因为用户所能看到的组件就是Activity
,所以Task可以理解为实现一个功能而负责管理所有用到的Activity
实例的栈。
其实查看源码,在Ams
内部,并不是真的有这么一个存放Activity
的Task
栈,Activity
还是通过ActivityStack
来管理,在ActivityRecord
中有一个TaskRecord
对象记录了真实的Activity
实例是属于哪个Task
的。Task
通过一个int
类型的TaskId
来唯一标识,该值在手机重启时将会被置零。
说了这么多,还是找一个Task
任务最直观的体现吧。先重启手机,长按home
键,发现弹出的最近任务中一个任务也没有,然后开启A应用,长按home
键,会发现有一个A应用的任务,查看手机进程,应该还没有B进程的;在A应用的A组件中调B应用的B组件,此时看手机的进程,除了A进程外,还有个B的进程,但是长按home键,能看到的还是只有一个A应用的任务。其实这个时候,B应用已经跑起来了,但是对用户来说,他其实没有开启过B应用,所以Task任务自始至终都是从用户的角度出发而设计的概念,保证用户的调用逻辑。
Activity、Application与进程的关系
理清楚了上述两个概念问题,进入Activity
的启动与Task
的关系之前,让我们先来了解下启动一个Activity
与apk Application
和进程的关系。对Activity
启动过程具体的分析,工程耗时很庞大,网上有个老罗整理的三篇博客,我看了半天还是云里雾里的。我通过我现在的认识和目前通过Demo
的测试来看,启动一个Activity
时,Ams
首先会去查询该Activity
所在的应用是否开启,如果没有开启则会启动一个进程去Run
这个Application
,因此无论通过Launcher
还是通过常规的程序内部调用startActivity
来启动一个Activity
,所要启动的Activity
都是跑在其注册的apk
所在的Application
进程中(或者该组件android:process
指定的进程中),而其TaskID
一般是和启动它的组件所属的TaskId
一致,但是也不尽然,这就要看下面的具体分析了。
另外通过对service
的应用,可以得出结论,一个apk
,即一个应用(Application)
可以跑在多个进程中,一个进程在一个虚拟机中运行,也即一个apk
可以启动多个虚拟机。
通过shareuserID
可以将多个apk
,跑在同一个进程中。
从而得出结论:一个虚拟机只能跑一个进程,一个进程里可以跑多个应用,一个应用也可以跑在多个进程中,这就是他们的关系。
Activity和Task的关系
启动一个Activity
有两种方式,一种就是通过Launcher
,另外一种是通过程序代码调用startActivity
函数实现(验证过AppWidget
其实与这种方式是一致的)其实影响Activity
启动关键点大致有三个因素:Activity
注册信息中的launchMode
、启动Activity
时Intent
中的launchFlags
和Activity
注册信息中的taskAffinity、allowTaskReparenting
、clearTaskOnLaunch
、alwaysRetainTaskState
、finishOnTaskLaunch
等信息。通常情况下,我们只需要针对第一个因素进行合理设置就能满足我们应用开发的需求了。
launchMode
的四种方式
launchMode
方法是在apk
的manifest
文件中针对每一个Activity
的android:launchMode
属性进行设置的方式,共有四种模式可以设置,分别是standard、singleTop、singleTask、singleInstance
,下面分别阐述之(由于其中几种因素有设置时,会影响lauchMode
的四种模式,所以下面情况下,其它因素都是缺省不设置的情况)。
standard
standard
是默认模式,即假设用户在manifest
中对Activity
不指定android:launchMode
的情况下,缺省启动模式即为standard。在启动一个以standard
为launchMode
的Activity
时,Ams
只是简单的创建一个新的Activity
实例,将其放到ActivityStack
(为了行文方便,后面将ActivityStack
简称AS
),其TaskId
则与启动这个Activity
的调用者Activity
相同(即就算创建一个新的进程,但是其TaskId
还是跟调用者一致的,以确保用户回退操作时保持一致)。这种是最常见的使用方式。
singleTop
启动一个以singleTop
为lauchMode
的Activity
时,Ams
会查询AS
:假如在AS
顶端正是要启动的Activity
实例,那么Ams
就不会重新启动一个Activity
实例,而是调用AS
栈顶的该Activity
实例的OnNewIntent
函数(自然不会修改原来的TaskId值);假如在AS
栈顶不是该Activity
的实例,那么就会创建一个新的实例,将其压入AS
,其TaskId
与调用者Activity
相同。这种方式主要用于避免自调自过程中,产生多个实例的情况。
singleTask
启动一个以singleTask
为lauchMode
的Activity
时,Ams
会查询AS
:如果AS
内有一个该类Activity
的实例,那么就会将该实例置于TS
的顶端(原来位于该实例上面的其它同TaskId
的activity
实例,将被销毁),并调用该实例的onNewIntent
函数;如果AS
内没有该类的实例,就会启动一个新的实例,将其压入AS
,其TaskID
与启动它的调用者没有必然关系,而是取决于该Activity
所在apk
进程是否有TaskId
,假如没有就会创建一个新的TaskId
。在实测中发现,如果singleTask
模式启动的Activity
是AS
中同TaskId
的最底部一个(或被称谓Task
栈的根实例),那么在通过桌面长按,在近期任务中跳转到Activity所在的任务时,即使该Activity
实例不是在栈顶,也会被置到栈顶(还会调用其onNewIntent
函数),并将AS
上同TaskId
的其它Activity
实例销毁,具体可以通过附带的demo来验证,其中TaskOne
中的Activity1
置成singleTask
启动模式,其它均为默认的standard
,其log
输出如下:
//在TaskTwo中启动Activity1,此前TaskOne apk没有在运行,所以启动Activity1时会申请一个新的TaskId,2afcfbd8这个Activity1成为了TaskId为53的Task栈栈底实例
04-05 16:21:27.144: E/ActivityB @2b003230(17933): onPause pid 17933 taskid 52
04-05 16:21:27.404: E/Activity1 @2afcfbd8(18489): onCreate pid 18489 taskid 53
04-05 16:21:29.214: E/ActivityB @2afecaf0(17933): onCreate pid 17933 taskid 53
04-05 16:21:30.254: E/Activity2 @2afdeef0(18489): onCreate pid 18489 taskid 53
04-05 16:21:30.894: E/ActivityB @2aff9328(17933): onCreate pid 17933 taskid 53
04-05 16:21:31.454: E/Activity2 @2afe9330(18489): onCreate pid 18489 taskid 53
04-05 16:21:31.864: E/ActivityB @2b009910(17933): onCreate pid 17933 taskid 53
04-05 16:21:32.424: E/Activity2 @2aff2570(18489): onCreate pid 18489 taskid 53
//通过长按跳转到TaskOne任务,此时在AS中id为53的在Activity1上面有6个
04-05 16:22:35.144: E/ActivityB @2afecaf0(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.144: E/Activity2 @2afdeef0(18489): onDestroy pid 18489 taskid 53
04-05 16:22:35.234: E/ActivityB @2aff9328(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.254: E/Activity2 @2afe9330(18489): onDestroy pid 18489 taskid 53
04-05 16:22:35.324: E/ActivityB @2b009910(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.344: E/Activity2 @2aff2570(18489): onPause pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onNewIntent pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onStart pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onResume pid 18489 taskid 53
04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onStop pid 18489 taskid 53
04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onDestroy pid 18489 taskid 53
singleInstance
启动一个以singleInstance
为launchmode
的Activity
时,假如AS
中已经有一个该类实例,那么调用其onNewIntent
函数;否则就会创建一个新的TaskId
,与该Activity
所在的apk
进程完全不同的TaskId
,而且这个TaskId
值以后也不会被用于其他任何Activity
实例中。
简单小结
一般我们开发普通的应用程序时,我们只需要使用缺省的standard
和singleTop
方式就够用了,不需要使用singleTask
和singleInstance
来声明注册的Activity
,因为它将破坏用户感觉上的回退操作,给用户使用上带来迷惑,所以一般将这两者用于很耗资源的Activity
,通过查看源码发现在源码packages\apps
中的程序,有如下一些应用使用了这两者高级设置
AndroidManifest.xml (packages\apps\browser): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\calendar): <activity android:name="AlertActivity" android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\contacts): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\email): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\launcher2): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\music): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\phone): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\phone): android:launchMode="singleInstance">
AndroidManifest.xml (packages\apps\quicksearchbox): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\settings): android:launchMode="singleTask"
AndroidManifest.xml (packages\providers\downloadprovider): android:launchMode="singleTask"
在上述分析中没有将其它两个因素引入,主要是自己在这方面接触的也比较少,而且这三方面因素共同组合会产生很多种不同效果,所以就没做具体展开。转载一些网友收集的资料如下:
跟Task有关的manifest文件中Activity的特性值介绍
android:allowTaskReparenting
用来标记Activity
能否从启动的Task
移动到有着affinity
的Task
(当这个Task
进入到前台时)
“true”
,表示能移动,“false”
,表示它必须呆在启动时呆在的那个Task
里。
如果这个特性没有被设定,设定到<application>
元素上的allowTaskReparenting
特性的值会应用到Activity
上。默认值为“false”
。
一般来说,当Activity
启动后,它就与启动它的Task
关联,并且在那里耗尽它的整个生命周期。当当前的Task
不再显示时,你可以使用这个特性来强制Activity
移动到有着affinity
的Task
中。典型用法是:把一个应用程序的Activity
移到另一个应用程序的主Task
中。
例如,如果 email
中包含一个web
页的链接,点击它就会启动一个Activity
来显示这个页面。这个Activity
是由Browser
应用程序定义的,但是,现在它作为email Task
的一部分。如果它重新宿主到Browser Task
里,当Browser
下一次进入到前台时,它就能被看见,并且,当email Task
再次进入前台时,就看不到它了。
Actvity
的affinity
是由taskAffinity
特性定义的。Task
的affinity
是通过读取根Activity
的affinity
决定。因此,根Activity
总是位于相同affinity
的Task
里。由于启动模式为“singleTask”
和“singleInstance”
的Activity
只能位于Task
的底部,因此,重新宿主只能限于“standard”
和“singleTop”
模式。
android:alwaysRetainTaskState
用来标记Activity
所在的Task
的状态是否总是由系统来保持。
“true”
,表示总是;“false”
,表示在某种情形下允许系统恢复Task
到它的初始化状态。默认值是“false”
。
这个特性只针对Task
的根Activity
有意义;对其它Activity
来说,忽略之。
一般来说,特定的情形如当用户从主画面重新选择这个Task
时,系统会对这个Task
进行清理(从stack
中删除位于根Activity
之上的所有Activivity
)。典型的情况,当用户有一段时间没有访问这个Task
时也会这么做,例如30分钟。
然而,当这个特性设为“true”
时,用户总是能回到这个Task
的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser
应用程序,这里有很多的状态(例如多个打开的Tab
),用户不想丢失这些状态。
android:clearTaskOnLaunch
用来标记是否从Task中清除所有的Activity
,除了根Activity
外(每当从主画面重新启动时)
“true”
,表示总是清除至它的根Activity
,“false”
表示不。默认值是“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”
。
前面文章:“Android四种Activity的加载模式”
已经详细描述,这里就不做描述了.
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
名。
跟Task有关的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()
,并且包含一个指向Activity B
的Intent
,那么,C和D都将结束,然后B接收到这个Intent
,因此,目前stack
的状况是:A,B。
上例中正在运行的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
。
这在你的程序有分割点的时候很有用。例如,一个e-mail
应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity
来显示。这个Activity
应该作为e-mail
应用程序Task
的一部分,因为这是用户在这个Task
中触发的操作。然而,当用户离开这个Task
,然后从主画面选择e-mail 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
中设置,并传递给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 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
中设置,并传递给Context.startActivity()
,这个标志将引发已经运行的Activity
移动到历史stack
的顶端。
例如,假设一个Task
由四个Activity
组成:A,B,C,D
。如果D
调用startActivity()
来启动Activity B
,那么,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 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
的顶端运行时,不再启动一个新的。