ActivityManagerService(AMS)是Android提供的一个用于管理Activity(和其他组件)运行状态的系统进程
AMS功能概述
和WMS一样,AMS也是寄存于systemServer中的。它会在系统启动时,创建一个线程来循环处理客户的请求。值得一提的是,AMS会向ServiceManager登记多种Binder Server如“activity” “meminfo” “cpuinfo”等——不过只有第一个“activity”才是AMS的“主业”,并由Activity ManagerService实现;剩余服务的功能则是由其他类提供的
先来看看AMS的启动过程。如下所示:
/*frameworks/base/services/java/com/android/server/SystemServer
.java*/
public void run() {
…
Slog.i(TAG, "Activity Manager");
context = ActivityManagerService.main(factoryTest); //启动AMS
…
ActivityManagerService.setSystemProcess(); //向ServiceManager注册
…
}
ActivityManagerService提供了一个静态的main函数,通过它可以轻松地启动AMS。然后还需要调用setSystemProcess来把这个重要系统服务注册到ServiceManager。由此可见它和WMS一样,都是“实名”
的Binder Server:
/*frameworks/base/services/java/com/android/server/am/ActivityM
anagerService.java*/
public static final Context main(int factoryTest) {
AThread thr = new AThread(); //创建AMS线程
thr.start(); //启动AMS线程
synchronized (thr) {
while (thr.mService == null) {/*注意,这段代码是运行在SystemServer所在线程中的。
所以通过mService是否为空来判断AMS成功启动与否:如果是的话就可以返回SystemServer 继续执行,否则就一直等待。Android在处理“系统级进程”出错时的普遍态度是“既然系统都出错 了,任何补救都是无力回天的”,所以它的异常处理部分经常是空的
*/
try {
thr.wait();
} catch (InterruptedException e) {
}
}
}
…
m.mMainStack = new ActivityStack(m, context, true); /*创建一个ActivityStack对象, 这是AMS的核心,很多工作都是围绕它展开的*/
…
return context;
}
对于SystemServer所在线程来说,它需要等到AThread(即上述的变量thr)成功启动后才能继续往下执行。所以当thr.start()后,就通过thr.wait()进入等待。那么,什么时候唤醒呢?答案就在AThread内部:
public void run() {…
synchronized (this) {
mService = m;
mLooper = Looper.myLooper();
notifyAll();
}
上面的notifyAll会唤醒所有在thr这个object所在等待队列上的目标,自然也就包括了SystemServer所属线程。这么做的原因是SystemServer的后续运行将依赖于AMS,所以如果在AMS还未就绪的情况下就贸然返回,很可能会造成系统宕机。
将AMS注册到ServiceManager很简单,唯一要注意的是它不只注册了自己一个Server,而是一系列与进程管理相关的服务。如下所示:
public static void setSystemProcess() {
try {
ActivityManagerService m = mSelf;
ServiceManager.addService("activity", m,
true);//AMS的主业
ServiceManager.addService("meminfo", new
MemBinder(m));//内存使用情况
…//其他服务省略
}
管理当前系统中Activity状态——ActivityStack
以下内容是从ActivityStack.java中提取出来的。
- 1.ActivityState
描述了一个Activity所可能经历的所有状态。其定义如下:
INITIALIZING, //正在初始化
RESUMED, //恢复
PAUSING, //正在暂停
PAUSED, //已经暂停
STOPPING, //正在停止
STOPPED, //已经停止
FINISHING, //正在完成
DESTROYING, //正在销毁
DESTROYED //已经销毁
} - 2.ArrayList
除了状态管理外,ActivityStack中还有一系列不同功能的ArrayList成员变量。它们的共同点在于列表元素都是ActivityRecord——这个类负责记录每个Activity的运行时信息。因而也可以看出,ActivityStack确实是AMS中管理Activity的“大仓库”。
- 3.记录特殊状态下的Activity
除了上面的ArrayList用来描述各种状态下的Activity集合外,ActivityStack还通过以下多个变量来专门记录一些特殊状态下的Activity实例,具体如表8-2所示。
以上所述的3类变量构成了ActivityStack的主框架。如果用一句话来简单概述AMS的功能,就是:
“AMS是通过ActivityStack(和其他数据结构)来记录、管理系统中的Activity(和其他组件)状态,并提供查询功能的一个系统服务。”这句话包含了以下几个重点。 - 1.AMS的主要工作就是管理、记录、查询
打个比方,AMS就像户籍登记处。所有新加入或者注销的家庭都需要到这里办理业务;而且它还提供对外的查询功能——这点类似于公安局开具的“户籍证明”,用于表明办证者当前的户口状态。 - 2.AMS是系统进程的一部分(确切地说它运行于一个独立的线程中)
从内核的角度来说,AMS其实也是普通进程中的一部分,只不过它提供的是全局性的系统服务。接着上面打的比方,户籍登记处和家庭一样,也是在一个“房子”(进程)里运行的。它有一套严格的办事规程(线程),来处理户主的各种请求(登记、注销、查询等)。值得一提的是,AMS的任务只是负责保管Activity(及其他组件)的状态信息,而像Activity中描述的UI界面如何在物理屏幕上显示等工作则是由WindowManagerService和SurfaceFlinger来完成的
startActivity流程
相信大家对startActivity(Intent)的功能不会陌生。它用于启动一个目标Activity——具体是哪个Activity则是AMS通过对系统中安装的所有程序包进行“Intent匹配”得到的,并不局限于调用者本身所在的package范围。换句话说,startActivity()最终很可能启动的是其他进程中的组件。当系统匹配到某个目标Activity后分为两种情况。
- 如果通过Intent匹配到的目标对象,其所属程序包中已经有其他元 素在运行(意味着该程序进程已启动),那么AMS就会通知这个 进程来加载运行我们指定的目标Activity。
- 如果当前Activity所属程序没有进程在运行,AMS就会先启动它的一个实例,然后让其运行目Activity。
先大致讲解一下startActivity()所经历的函数调用流程,从调用方(Activity1)开始:Activity1→
startActivity@ContextImpl.java→execStartActivity@Instrumentation.java→startActivity@ActivityManager Service.java。
因而经过层层中转后,调用者发起的startActivity最终还是在AMS中实现的。接下来的问题就转化为:AMS内部对startActivity是如何处理的?
看似简单的一个功能,实际上AMS要做的工作还是很多的——首先来辨别下AMS中5个“长相”类似的
startActivity函数,以防后期混淆。统一列出如下:
startActivity@ActivityManagerService.java
startActivityAsUser@ ActivityManagerService.java
startActivityMayWait@ActivityStack.java
startActivityLocked@ActivityStack.java
startActivityUncheckedLocked@ActivityStack.java
这5个函数存在先后调用的关系。源代码如下:
/*frameworks/base/services/java/com/android/server/am/ActivityMa
nagerService.java*/
public final int startActivity(IApplicationThread caller,
String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd,
Bundle options) {
return startActivityAsUser(caller, callingPackage,
intent, resolvedType,
result To, resultWho, requestCode,
startFlags,
profileFile, profileFd,
options,UserHandle.getCallingUserId());
}
可以看到,startActivityAsUser与startActivity只多了最后一个参数userId,它表示调用者的用户ID值,因而可以通过Binder机制的getCallingUid获得:
public final int startActivityAsUser(IApplicationThread
caller, String calling Package,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile,
ParcelFileDescriptor profileFd, Bundle options, int
userId {
enforceNotIsolatedCaller("startActivity");
userId = handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId,
false, true, "startActivity", null);
return
mMainStack.startActivityMayWait(caller,-1,callingPackage,intent,
resolvedType,
resultTo, resultWho, requestCode, startFlags,
profileFile, profileFd,
null, null, options, userId);/*这个函数是ActivityStack提供的*/
}
函数startActivityAsUser的一大重点就是做权限检查,包括:
- enforceNotIsolatedCaller
检查调用者是否属于被隔离的对象。 - handleIncomingUser
调用者是否有权力执行这一操作
5个“startActivityXX”其实是5个执行步骤,而且一旦其中一步出现错误就会中止整个流程。接着往下分析startActivityMayWait这个函数。因为代码很长,我们直接把其中的核心工作提取出来,如图8-2所示。
根据图8-2中的描述,在startActivityMayWait中: - 要启动某个符合Intent要求的Activity,那么首先就应确定这个目标Activity:如果是显式的Intent,问题很好解决,因为Intent信息中已经带有目标Activity的相关信息;否则就调用resolveActivity()进行查找
- 判断目标Activity所属进程是不是重量级(heavy-weight)的。如果当前系统中已经存在的重量级进程(mService.mHeavyWeightProcess)不是即将要启动的这个,那么就要给Intent重新赋值。
- 调用startActivityLocked来进一步执行启动工作。
- 如果outResult不为空,还需要将函数的结果写入这个变量中。
这个函数的名称表明它有可能会“wait”——具体就表现在对outResult的处理上。
AMS中startActivity的过程如图8-5所示。
完成同一任务的“集合”——Activity Task
Android系统中应用程序的一大特色,就是它们不仅可以“装载”众多系统组件,而且可以把这些组件跨进程地组成ActivityTask。这个特性使得每个应用都不是孤立的,从而能最大限度地实现资源复用。举个例子,一个短信应用程序至少会有“已收短信列表”、“阅读短信”和“编辑短信”3个子功能——在Android体系中它们分别对应3个Activity。
从程序包(Package)的组织角度来说,这3个元素只属于“短信”这个程序。但事实上,Activity的设计意图已经超越了单一的进程概念。换句话说,这几个Activity不仅在“短信”这一程序可以非常方便地互相调用(比如用户在“已收短信列表”中点击任何一条短信就可以进入“短信阅读”),其他需要使用“短信”功能的进程也能通过startActivity(Intent)来复用它们。比如我们在浏览电话本时,可以将某个人的联系方式通过短信发送出去。电话本程序并不需要专门实现短信的编辑和发送,只需填写这一请求(Intent),然后利用startActivity(Intent)告诉系统,余下的事情就会有相应的“志愿者”去帮它完成。
在这一过程中,系统先后启动了“联系人详情”和“短信编辑”两个不同进程中的Activity,来共同完成“通过短信发送联系人信息”的任务,这就是ActivityTask概念的直观体现。从数据结构的角度来讲,Task有先后之分,所以源码实现上采用了Stack栈的方式。在本例中,“联系人详情”这个Activity是首先启动并被压栈的,随后“栈顶”的位置被“短信编辑”所取代——直到短信发送完成后被销毁,此时就又会“显示”出原来的那个“联系人详情”的Activity了。
ActivityTask机制打破了应用程序的常规使用界限,从而增强了用户体验。同时,也给程序的管理和实现增加了一定难度。上面已经说过,Task运用的是“栈”管理方式,那么在AMS中具体是如何实现的呢?当前系统应该不仅有一个Task,而是众多Task的集合,这些Task间又有什么联系?用户是否可以控制和调整这些Task间的联系呢?
回答是肯定的。Android系统提供了一系列Flag标志来允许用户对Task进行实时调整,正确理解和使用这些flag无疑会让应用程序更贴近用户的使用习惯。
1.1 “后进先出”——Last In,First Out
传统意义上“栈”的思想就是“Last In, First Out”。通俗地讲,就是“后进先出”——先入栈的元素会被压在栈底,而后续元素不断往上堆栈。因而出栈时自然是最后的那个元素在先,然后才是下面的元素,直到栈底。
从上述“栈”的概念来衡量,ActivityTask并不能算是严格意义的Stack——它在默认情况下和栈是一致的,但比栈提供了更多的操作方式,因而可以理解为“栈的一种变异”。
1.2 管理Activity Task
前一小节所述的Activity Task已经能满足开发者的一般需求,但是在某些情况下我们还希望拥有更多的灵活性。比如在启动一个新的Activity时,我们可能不希望它和当前的Activity处于同一个Task中;或者我们希望当新的Activity运行时,系统可以先清空当前的Task等。Android系统提供了丰富的接口方法来满足程序员的类似需求
应用程序可以通过两种方法来影响Activity Task的默认行为。
方法1:在< activity>标签中指定属性
- android:taskAffinity
Affinity即“喜好,倾向”,它代表这个Activity所希望归属的Task。在默认情况下,同一个应用程序中的所有Activity拥有共同的Affinity,即<AndroidManifest.xml>中声明的Package Name。当然也可以主动在< application>中使用taskAffinity标签属性来指定整个应用程序的Affinity。
一个Activity Task的Affinity属性取决于它的根Activity。
那么,taskAffinity在什么情况下产生效果?
(1)当启动Activity的Intent中带有FLAG_ACTIVITY_NEW_TASK标志时
在默认情况下,目标Activity将与startActivity的调用者处于同一Task中。但如果用户特别指定了FLAG_ACTIVITY_NEW_TASK,表明它希望为Activity重新开设一个Task。这时就有两种情况:假如当前已经有一个Task,它的affinity与新Activity是一样的,那么系统会直接用此Task来完成操作,而不是另外创建一个Task;否则系统需要重启一个Task。
(2)当Activity中的allowTaskReparenting属性设置为true时。在这种情况下,Activity具有“动态转移”的能力。举个前面的“短信”例子,在默认情况下该应用程序中的所有Activity具有相同的affinity。当另一个程序启动了“短信编辑”时,一开始这个Activity和启动它的Activity处于同样的Task中。但如果“短信编辑”Activity指定了allowTaskReparenting,且后期“短信”程序的Task转为前台,此时“短信编辑”这一Activity会被“挪”到与它更亲近的“短信”Task中。
- android:launchMode
用于指定Activity被启动的方式。主要包括两方面的内容:即Activity是否为单实例以及Activity归属的Task。不论是何种方式,最终被启动的Activity通常情况下都要位于ActivityTask的栈顶(因为只有在栈顶的Activity才是可以直接与用户交互的)。一共有4种launchMode,如表8-3所示。
关于启动模式,看一下官网的介绍
android:launchMode
有关应如何启动 activity 的指令。共有五种模式可与 Intent 对象中的 activity 标记(FLAG_ACTIVITY_* 常量)协同工作,以确定在调用 activity 处理 intent 时应执行的操作。它们是:
“standard”
“singleTop”
“singleTask”
“singleInstance”
“singleInstancePerTask”
默认模式为“standard”。
如下表所示,这些模式可分为两大类:“standard”和“singleTop”activity 为一类,“singleTask”“singleInstance”和“singleInstancePerTask”activity 为另一类。启动模式为“standard”或“singleTop”的 activity 可以多次实例化。实例可归属任何任务,并且可位于 activity 任务中的任何位置。通常,它们会启动到名为 startActivity() 的任务中(除非 intent 对象包含 FLAG_ACTIVITY_NEW_TASK 指令,在此情况下会选择其他任务 - 请参阅 taskAffinity 属性)。
相比之下,“singleTask” “singleInstance” 和 “singleInstancePerTask” activity 的行为有所不同。“singleInstancePerTask”始终位于 activity 任务的根位置。此外,设备一次只能保留一个 “singleInstance” activity 实例,而 “singleInstancePerTask” activity 在 FLAG_ACTIVITY_MULTIPLE_TASK 或 FLAG_ACTIVITY_NEW_DOCUMENT 已设置的情况下,在不同的任务中可以多次实例化。启动模式为 “singleTask” 的 activity 结合了 “singleInstance” 和 “singleInstancePerTask” 的行为:activity 可以多次实例化,并且可以位于具有相同 taskAffinity 的任务中的任意位置。同时,设备只能保留一个用于在 activity 任务的根位置查找 “singleTask” activity 的任务。
“standard”和“singleTop”模式只有一个不同之处:每次“standard”activity 有一个新的 intent 时,系统都会创建类的新实例来响应该 intent。每个实例处理单个 Intent。同样地,您也可以创建新的“singleTop”activity 实例来处理新的 intent。不过,如果目标任务的 activity 堆栈顶部已有一个 activity 实例,则该实例会(通过调用 onNewIntent())接收新的 intent;此时不会创建新实例。在其他情况下(例如,如果“singleTop”activity 的某个现有实例虽在目标任务内,但未处于堆栈顶部,或者虽然位于堆栈顶部,但不在目标任务中),系统会创建新实例并将其送入堆栈。
同样地,如果您向上导航到当前堆栈上的某个 activity,则该行为由父 activity 的启动模式决定。如果父 activity 有启动模式 singleTop(或者 up intent 包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将该父项置于堆栈顶部,并保留其状态。导航 Intent 由父 Activity 的 onNewIntent() 方法接收。如果父 activity 有启动模式 standard(并且 up intent 不包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将当前 activity 及其父项同时送出堆栈,并创建新的父 activity 实例来接收导航 intent。
“singleInstance”模式也与“singleTask”和“singleInstancePerTask”有一个不同之处:具有“singleTask”或“singleInstancePerTask”启动模式的 activity 允许其他 activity(必须是“standard”和“singleTop”activity)成为其任务的一部分。另一方面,“singleInstance”activity 不允许任何其他 activity 成为其任务的一部分;它必须是任务中唯一的 activity。如果它启动另一个 activity,则系统会将该 activity 分配给其他任务,就如同 intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。
如上表所示,standard 是默认模式,适用于大多数类型的 activity。对众多类型的 activity 而言,SingleTop 也是常见且有用的启动模式。其他模式(singleTask、singleInstance 和 singleInstancePerTask)不适用于大多数应用,因为它们所形成的交互模式可能让用户感到陌生,并且与大多数其他应用差别较大。
关于启动模式,进行一些补充,来源于《Android开发艺术探索》
( 1) standard:标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下Activity 的生命周期,它的 onCreate、onStart、onResume都会被调用。这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个 Activity,那么这个 Activity就运行在启动它的那个Activity所在的栈中。比如 Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈中。不知道读者是否注意到,当我们用ApplicationContext去启动standard模式的Activity的时候会报错,错误如下:
相信这句话读者一定不陌生,这是因为 standard模式的Activity 默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如 ApplicationContext)并没有所谓的任务栈,所以这就有问题了。解决这个向题的方法是为待启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为它创建一个新的任务栈,这个时候待启动Activity实际上是以 singleTask模式启动的。
(2) singleTop:栈顶复用模式。在这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的造,这个Activity 的 onCreate、onStart不会被系统调用,因为它并没有发生改变。如果新Activity 的实例已存在但不是位于栈顶,那么新Activity仍然会重新重建。举个例子,假设目前栈内的情况为ABCD,其中 ABCD为四个 Activity,A位于栈底,D位于栈顶,这个时候假设要再次启动D,如果D的启动模式为singleTop,那么栈内的情况仍然为ABCD;如果D的启动模式为standard,那么由于D被重新创建,导致栈内的情况就变为ABCDD。
(3 ) singleTask:栈内复用模式。这是一种单实例模式,在这种模式下,只要 Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和 singleTop一样,系统也会回调其 onNewIntent。具体一点,当一个具有singleTask模式的Activity请求启动后,比如Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需的任务栈,这时要看A是否在栈中有实例存在,如果有实例存在,那么系统就会把A调到栈顶并调用它的
onNewIntent方法,如果实例不存在,就创建A的实例并把A压入栈中。举几个例子:
- 比如目前任务栈S1中的情况为ABC,这个时候Activity D以singleTask模式请求启动,其所需要的任务栈为S2,由于S2和D的实例均不存在,所以系统会先创建任务栈S2,然后再创建D的实例并将其入栈到S2。
- 另外一种情况,假设D所需的任务栈为S1,其他情况如上面例子1所示,那么由于S1已经存在,所以系统会直接创建D的实例并将其入栈到S1。
- 如果D所需的任务栈为S1,并且当前任务栈S1的情况为ADBC,根据栈内复用的原则,此时D不会重新创建,系统会把D切换到栈顶并调用其 onNewIntent方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是最终S1中的情况为AD。
( 4)singleInstance:单实例模式。这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。
- android:clearTaskOnLaunch
清除Task中所有除root activity的元素。可想而知这个属性只对root activity设置有效,task中其他activity设置此属性是无效的。 - android:alwaysRetainTaskState
如果用户在一定时间内不再访问Task,比如说30分钟,那么系统就有可能会清除task中的状态(只保留root activity)。设置此属性为“true”可以避免这种情况。 - android:finishOnTaskLaunch
当Task被再次启动时,activity是否需要销毁。这个属性比allowTaskReparenting优先级高。也就是说,这种情况下activity不
会被重新指定task,而是直接销毁。
方法2:使用Intent标志
除了在标签中声明task属性外,我们也可以在启动一个Activity(startActivity)时通过Intent来动态指定所需的task属性值。Activity中静态标注的属性和后面startActivity所指定的Intent有冲突则以Intent为准。
- FLAG_ACTIVITY_NEW_TASK
这个和前面的singleTask启动模式的作用是一样的。 - FLAG_ACTIVITY_SINGLE_TOP
这个和前面的singleTop启动模式的作用是一样的。 - FLAG_ACTIVITY_CLEAR_TOP
和上面两个不同,launchMode中没有与此对应的模式。它所代表的含义是:如果要启动的Activity已经在当前task中运行,那么所有在它之上的Activity都将被销毁,并且Intent通过onNewIntent传给它(这时它会被resumed)。
另外还有几个Intent标志对我们分析AMS有帮助,一并列出如下。
- FLAG_ACTIVITY_NO_HISTORY
这个Activity将不会被保存在History Stack中。同样的效果也可以通过在AndroidManifest.xml中添加“android:noHistory”来实现。 - FLAG_ACTIVITY_MULTIPLE_TASK
这个标志需要和FLAG_ACTIVITY_NEW_TASK一同使用,否则没有效果。它将阻止系统恢复一个现有的task(比如我们要启动的Activity已经在这个Task中)。换句话说,系统总是启动一个新的task来容纳要启动的Activity。 - FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置了这个标志,则Activity不会被放在系统“最近启动的Activity列表”中。 - FLAG_ACTIVITY_BROUGHT_TO_FRONT
在launchMode中使用了singleTask后,系统会自动加上这个标志。 - FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
使用此标志,当Activity在新task中启动或者在已有task中启动,都会处于task的上端。 - FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
系统自动设置的,说明这个Activity是从历史记录中启动的(长按HOME键可以调出)。 - FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
一般情况下,当从Launcher启动应用程序Activity时都带有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,这样Task中所有此Activity上面的Activity都将被finish。这个标志就是辅助完成这个功能的。 - FLAG_ACTIVITY_NO_USER_ACTION
Activity中的onUserLeaveHint回调用于指示用户将要离开,它会退出前台。某些情况下这并不是用户主动选择造成的。比如当系统有来电(Incoming Call)或者闹钟事件,由此弹出的Activity都不是用户主动去点击启动的,因而带上这个标志可以使前述的回调函数不得到执行。 - FLAG_ACTIVITY_REORDER_TO_FRONT
设置此标志后,如果将要启动的Activity已经在History Stack中运行,那么我们只是调整其中的顺序将其放到最前端。 - FLAG_ACTIVITY_NO_ANIMATION
此标志表示启动的Activity不需要应用动画效果。 - FLAG_ACTIVITY_CLEAR_TASK
此标志将清除与启动的Activity相关task中的其他元素,只能与FLAG_ACTIVITY_NEW_TASK一起用。 - FLAG_ACTIVITY_TASK_ON_HOME
新启动的Activity将被放在task中Launcher的上面(如果存在的话),这样它返回时就会是Launcher了。此标志只能与FLAG_ACTIVITY_NEW_TASK一起用。