您的位置:首页 > 移动开发 > Android开发

AMS分析--基于深入理解android(2)

2016-08-16 17:13 288 查看
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;

int launchFlags = intent.getFlags();

/// M: AMS log enhancement @{
if (!ActivityManagerService.IS_USER_BUILD)
Slog.i(TAG, "ACT-launchFlags(original): 0x" + Integer.toHexString(launchFlags) + ", launchMode:" + r.launchMode
+ ", startFlags: " + startFlags + ", doResume:" + doResume);
/// @}

// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;//加上FLAG_ACTIVITY_NO_USER_ACTION这个标志,系统就不会调用onUserLeaveHint
//比如用户主动切换任务,短按home进入桌面等会调用onUserLeaveHint,系统自动切花activity不会调用此方法,如来电,灭屏等


//当用户按Home键等操作使程序进入后台时 就会根据mUserLeaving=true,

//调用onUserLeaveHint(),

//onUserLeaveHint

//这个回调函数主要用来监听按Home键退出到桌面的动作,发生在onPause之前。在启动一个新的Activity时,

//ActivityStackSupervisor里会调用startActivityUncheckedLocked,在它里面会给mUserLeaving赋值。

//mUserLeaving用于指示当前activity退到后台时函数onUserLeaving是否被调用。

//可见,只有当设置了FLAG_ACTIVITY_NO_USER_ACTION标志时mUserLeaving才会为false,

//其他情况下mUserLeaving均为true,也就是onUserLeaveHint会被调用,注释里也说了onUserLeaveHint会在onPause之前被调用。

//例子可以查看 http://www.2cto.com/kf/201503/380568.html

android onUserLeaveHint和onUserInteraction

onUserLeaveHint 当用户的操作使一个activity准备进入后台时,此 方法会像activity的生命周期的一部分被调用。例如,当用户按下 Home键,

Activity#onUserLeaveHint()将会被回调。但是当来电导致来电activity自动占据前台,Activity#onUserLeaveHint()将不会被回调。

onUserLeaveHint() 用户手动离开当前activity,会调用该方法,比如用户主动切换任务,短按home进入桌面等。系统自动切换activity不会调用此方法,如来电,灭屏等。

onUserInteraction() activity在分发各种事件的时候会调用该方法,注意:启动另一个activity,Activity#onUserInteraction()会被调用两次,一次是activity捕获到事件,另一次是调用Activity#onUserLeaveHint()之前会调用Activity#onUserInteraction()。

if (!doResume) {
r.delayedResume = true;//还没有恢复的app  switch
}
//启动Activity时默认不会设置FLAG_ACTIVITY_PREVIOUS_IS_TOP
//故此notTop默认情况下会是null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//ActivityRecord checkedCaller优先等于sourceRecord,其次选择正在运行的Activity
//如果调用者和被启动的对象是同一个,不不需要重复启动 所以START_FLAG_ONLY_IF_NEEDED 可以置位空
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.//调用者和启动这不一致,所以是启动必须的,置位意思非必须的
startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
}
}


//根据sourceRecord的情况进行对应处理,能理解下面这段if/else的判断语句吗
if(sourceRecord == null) {
//如果请求的发起者为空,则当然需要新建一个Task
if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0)
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}else if (sourceRecord.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
//如果sourceRecord单独占一个Instance,则新的Activity必然处于另一个Task中
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//如果启动模式设置了singleTask或singleInstance,则也要创建新Task
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}//if(sourceRecord== null)判断结束


ActivityInfo newTaskInfo = null;
Intent newTaskIntent = null;
final ActivityStack sourceStack;
if (sourceRecord != null) {
if (sourceRecord.finishing) {

//如果sourceRecord已经处于finishing状态,那么他所在的Task就很有可能已经为空或者即将为空。
//我们就不能盲目throw it in to that task。
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + sourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
newTaskInfo = sourceRecord.info;
newTaskIntent = sourceRecord.task.intent;
}
sourceRecord = null;
sourceStack = null;
} else {
sourceStack = sourceRecord.task.stack;
}
} else {
sourceStack = null;
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//如果启动的activity需要新的task,那么新启动的activity将会与其caller断开依赖关系
//,这个关系主要是指result反馈,A-->B,如果A是通过startActivityForResult()请求启动的,并且requestCode >=0,那么如果B是在新的task中
//,那么B在finish的时候将不再向A反馈result,而是在启动过程中就会向A反馈一个RESULT_CANCELED。

Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
r.resultTo.task.stack.sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
}//禁止两个task之间通信,发送取消发送结果消息给调用者


if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {

if (r.resultTo == null) {
//因为是启动新的task,所以r.resultTo 必须被以上函数设置为null

ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(r)//从所有Stack中的所有Task中的Activity中查找看能否找到要启动的Activity,根据要启动的Activity启动模式是否是SingleInstance所采用的搜索方法是不一样的。
: findActivityLocked(intent, r.info);
if (intentActivity != null) {
if (r.task == null) {
r.task = intentActivity.task;
}
targetStack = intentActivity.task.stack;
targetStack.mLastPausedActivity = null;
if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
+ " from " + intentActivity);
moveHomeStack(targetStack.isHomeStack());//rus启动桌面
if (intentActivity.task.intent == null) {

intentActivity.task.setIntent(intent, r.info);


以下3种条件需要检查是否有有task可复用

⑴ (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;

⑵ r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK

⑶ r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE

第⑴是一个组合条件,Intent.FLAG_ACTIVITY_MULTIPLE_TASK不能单独使用,它是和Intent.FLAG_ACTIVITY_NEW_TASK结合起来使用的,如果设置了Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那么将会永远启动一个新的task,不管是否有可复用的task。


为什么是这3种条件,从android的开发文档中,我们可知LAUNCH_SINGLE_TASK和LAUNCH_SINGLE_INSTANCE两种launch mode的activity只允许作为task的root activity,既然是作为root activity,那么它所处的task的affinity必然是和它的是一样的,因此从mHistory中找打一个和自己的affinity相同的task是非常有必要的。

而对于设置了Intent.FLAG_ACTIVITY_NEW_TASK的Intent来说,并且没有设置Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那么同样的,它也必须是作为它所处的task的root activity。道理是一样的。

AMS去mHistory中查找可复用的task,查找这个task的规则如下:

⑴ launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,遵循如下规则: @findTaskLocked()

① 查找mHistory中是否有与要启动的activity相同affinity的task,上面也提过这几类activity启动时,均是作为task的root activity,并且其task的affinity必须和自己的affinity相同,因此首先需要去mHistory查找和自己affinity相同的task。

② 如果activity没有affinity,即属性android:taskAffinity设置为“”,空字符串时。此时AMS就会去mHistory中去查找是否有task的root activity和启动的activity相同,通过比较task.intent.getComponent()和启动activity的Comeponent比较,为什么是root activity,前面分析过了;

③ 如果task.Intent为空,这种情况发生在TaskReparenting之后,TaskReparenting之后,AMS为这个activity创建一个新的task,并将启动这个activity的Intent赋值给task.affinityIntent,并且此时的task.Intent==null。此时就需要比较task.affinityIntent.getComponent()和启动activity的Comeponent比较,看是否和启动的activity相同。

以上3个规则中,均是返回找的task中最上面的activity,而不一定是task的activity,至于如何处理要启动的activity和task中已有的activity,后面会介绍。

⑵ launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,遵循如下规则: @findActivityLocked()

对于ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式来说,它所处的task中只允许有它一个activity,因此它的规则只符合上面规则中的②;

对于第①条,由于设置了ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity,它只能自己独处一个task,不可能和别人共享同一个task,因此mHistory即使存在了与该activity有相同的affinity的activity,如果这个activity和启动的activity不同,那么ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity也不可能和它共用一个task,因此这第①条完全可以不用检查。

对于第②条,由于该模式的activity独处一个task,因此完全没有可能所处的task的affinity和自己的affinity不同,因此,假如mHistory存在相同的activity与启动的activity相同,那么这个activity的affinity必然和自己的相同。所以对于这种模式,第②条囊括了其他模式的①②两条。

对于第③条,同样的道理,ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity不可能处在与自己不同affinity的task中,因此不可能出现TaskReparenting操作,所以这条也不需要。


+++++++++++++++++

什么是Affinity

在某些情况下,Android需要知道一个Activity属于哪个Task,即使它没有被启动到一个具体的Task里。这是通过任务共用性(Affinities)完成的。任务共用性(Affinities)为这个运行一个或多个Activity的Task提供了一个独特的静态名称,默认的一个活动的任务共用性(Affinity)是实现了该Activity的.apk包的名字。

当开始一个没有Intent.FLAG_ACTIVITY_NEW_TASK标志的Activity时,任务共用性affinities不会影响将会运行该新活动的Task:它总是运行在启动它的Task里。但是,如果使用了NEW_TASK标志,那么共用性(affinity)将被用来判断是否已经存在一个有相同共用性(affinity)的Task。如果是这样,这项Task将被切换到前面而新的Activity会启动于这个Task的顶层。

这种特性在您必须使用NEW_TASK标志的情况下最有用,尤其是从状态栏通知或桌面快捷方式启动活动时。结果是,当用户用这种方式启动您的应用程序时,它的当前Task将被切换到前台,而且想要查看的Activity被放在最上面。

你可以在程序清单(Manifest)文件的应用程序application标签中为.apk包中所有的活动分配你自己的任务共用性Affinites,或者在活动标记中为各个活动进行分配。

一些说明其如何使用的例子如下:

如果您的.apk包含多个用户可以启动的高层应用程序,那么您可能需要对用户看到的每个Activity(活动)指定不同的affinities。一个不错的命名惯例是以附加一个以冒号分隔的字符串来扩展您的.apk包名。例如,“ com.android.contacts ”.apk可以有affinities:“com.android.contacts:Dialer”和“ com.android.contacts:ContactsList”。
如果您正在替换一个通知,快捷方式,或其他可以从外部发起的应用程序的“内部”活动,你可能需要明确设定您替代活动的taskAffinity和您准备替代的应用程序一样。例如,如果您想替换contacts详细信息视图(用户可以创建并调用快捷方式),你得把taskAffinity设置成“com.android.contacts”。

跟 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不会重新宿主,但是会销毁。

跟 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_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_SINGLE_TOP

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


+++++++++++++++++++

// if the caller is not itself in the front.
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);//检测当前在堆栈顶端的Activity是否就是即将要启动的Activity
/* 这段代码的逻辑是看一下,当前在堆栈顶端的Activity是否就是即将要启动的Activity,有些情况下,如果即将要启动的Activity就在堆栈的顶端,*/
/*那么,就不会重新启动这个Activity的别一个实例了,*/
/*现在处理堆栈顶端的Activity是Launcher,与我们即将要启动的MainActivity不是同一个Activity,因此,这里不用进一步处理上述介绍的情况*/
if (curTop != null && (curTop.task != intentActivity.task ||
curTop.task != lastStack.topTask())) {
//当 notTop !=null ,此时有可能 curTop.task != lastStack.topTask                     r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);//因为系统中存在这个Activity,所以把它拿到前台。不新建
//可以参考这篇http://www.2cto.com/kf/201407/319948.html
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;//movedHome表示是否移动home task
targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
//这一步,将已经存在的我们的目标Task终于被移动到了前台!参数intentActivity.task就是我们搜索出来的我们要启动
//的Activity所在的Task,r就是我们要启动的ActivityRecord。
if ((launchFlags &
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity.
intentActivity.task.mOnTopOfHome = true;//把当前新启动的任务置于Home任务之上,也就是按back键从这个任务返回的时候会回到home
//,即使这个不是他们最后看见的activity
}
options = null;
/// M: Fix ALPS01276300, at this case, avoid move home to top when resume top @{
intentActivity.task.mMovingToFront = true;
/// @}
}


Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP

检查Intent是否设置了Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,这个标志我有点困惑,从它的注释可以看出它的含义是指如果设置了该flag,那么mHistory中最top的activity在后续的处理中将不被视为top,而将前一个activity视为top,如A–>B–>C,将B视为top。

这个top activity的作用很大,涉及到后面对task的处理。但是目前来看这个flag并没有起到该有的作用,代码中判断如果设置了该标志,那么AMS将会视当前正在启动的activity为top,然后去mHistory中去查找它的前一个activity为后续task处理的top activity(topRunningNonDelayedActivityLocked()中实现),但是现在的问题是此时此刻,正在启动的activity并不存在于mHistory中,因为我们在前一个函数中刚刚创建了这个ActivityRecord。如下面代码所示:

[java] view plaincopy

ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)

!= 0 ? r : null;

因此,感觉这个flag的意义不是太大

// If the caller has requested that the target task be
// reset, then do so.
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
}
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and
// the client said not to do anything if that
// is the case, so this is it!  And for paranoia, make
// sure we have correctly resumed the top activity.
if (doResume) {
//默认情况下startFlags不会设置START_FLAG_ONLY_IF_NEEDED,调用者和启动这不一致,所以是启动必须的,置位意思非必须的
resumeTopActivitiesLocked(targetStack, null, options);
} else {
ActivityOptions.abort(options);
}
/// M: Add debug task message @{
if (DEBUG_TASKS) {
Slog.i(TAG, "START_RETURN_INTENT_TO_CALLER, doResume = " + doResume);
}
/// @}
if (r.task == null)  Slog.v(TAG,
"startActivityUncheckedLocked: task left null",
new RuntimeException("here").fillInStackTrace());
return ActivityManager.START_RETURN_INTENT_TO_CALLER;


FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:如果设置该属性,并且这个activity在一个新的task中正在被启动或者被带到一个已经存在的task的顶部,这时这个activity将会被作为这个task的首个页面加载。这将会导致拥有这个应用的affinities的task处于一个合适的状态(移动activity到这个task或者activity从中移出),或者简单的重置这个task到它的初始状态


http://blog.csdn.net/windskier/article/details/7096521

Reset Task

如果Intent设置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,最常见的情况,当从Home启动应用程序时,会设置这个flag;从recently task进入应用程序,则不会设置这个falg。

设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,AMS会对复用的task作如下处理,下面称这个可复用的task为复用task:

⑴ mHistory中,对于复用task中的除root activity外的activity,有如下处理

在此之前,先介绍activity的几个关键属性:

① 如果复用task在后台时间超过30min,那么在这个过程中将删除除root activity之外的所有的activity;

② 如果新启动的activity设置了属性ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE,那么表明它并不要求后台20min的复用task删除activity;

③ 如果新启动的activity设置了属性ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH,那么表明不论复用task在后台是否超过30min,一律要求删除除root activity之外的所有的activity;

④ 复用task中的activity设置了属性ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH,那么复用task从home中再次被启动到前台时,这个activity会被删除;

⑤ 复用task中的activity设置了属性ActivityInfo.FLAG_ALLOW_TASK_REPARENTIN,并且这个activity的resultTo为空,那么也就是说这个activity和它的caller没有依赖关系,那么AMS认为这个activity暂时没有用处了,需要对其进行TaskReparenting操作,最好的方法是把它放到mHistory栈底,不影响其他task。

⑥ 复用task中的activity的Intent设置属性Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那么下次再从home中进入到task中,那么将删除设置了该属性的activity以上所有的activity,例如A–>B–>C–>D–>E,加入在C启动D时设置了该属性,那么下次从HOME中再次进入到这个task中时,将会是A–>B–>C。

⑦ 如果复用task中的activity的resultTo不为空,也就是启动这个activity的是一个activity,那么这个activity的处理将按照它的前一个activity的处理方式来处理,不管在何时情况下,它的前一个activity都是启动它的activity,即便resultTo不是前一个activity,如设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT。如果复用task中每个activity的resultTo都不为空,并且上述处理优先级在其前面的属性没有设置的话,那么这个复用task中的activity将不作任何的处理。

一般情况下,activity的resultTo都不为空,除非设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT,那么此时被启动的activity的caller的resultTo将会为空。

task中的activity的属性设置是上述属性的组合,因此reset task过程要按照一定的优先级来处理,上述属性的处理优先级是:⑥=④>⑦>⑤>③=②>①

具体操作顺序如下:

♣ 根据⑥,④条件来删除复用task中相应的activity;

♣ ⑦条件下,将会暂时不做处理,再根据它的前一个activity的属性来做处理,即使这个activity设置了allowTaskReparenting;

♣ 如果activity的resultTo为空,并且满足条件⑤,那么将其及其以上未作处理的,满足条件⑦的所有activity,一并进行TaskReparenting操作,并放置在mHistory栈底。它们在mHistory栈底顺序如同在复用task中的顺序;

♣ 根据①②③的条件来删除复用task中相应的activity。

⑵ mHistory中,不属于复用task的activity,并且它的resultTo不为空,那么将根据它的前一个activity的处理来处理;

⑶ mHistory中,不属于复用task,但是和当前启动的activity有相同affinity,并且允许TaskReparenting操作,那么将进行以下操作:

♣ 如果满足上述的①②③④的条件,但是其中的task不是复用task,而是这个activity所处的task,那么将输出这个activity,而不是进行TaskReparenting操作。

为什么非复用task中的activity,和当前启动的activity有相同affinity,并且允许TaskReparenting操作,满足了①②③④的条件之后要删除呢,为什么非复用task中的其他activity,不需要删除呢?

正因为它和启动的activity有相同的affinity,因此AMS认为这个activity是和启动activity相关的,以后可能会重新调用,所以当其满足删除条件后,这时它将不允许TaskReparenting操作,并且不应该再允许它存在于其他的task中,此时应该删除。

♣ 如果没有满足①②③④的条件,那么将会对其进行TaskReparenting操作,重新将其移动到复用task或新启动的task中。

if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any
// existing task with its new activity.  Well that should
// not be too hard...
reuseTask = intentActivity.task;
reuseTask.performClearTaskLocked();//清空所有的Activity
reuseTask.setIntent(r.intent, r.info);
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0  // 启动之后删除其他Activity
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
ActivityRecord top =
intentActivity.task.performClearTaskLocked(r, launchFlags);
// 这3种条件有一个共同点,就是启动的activity启动之后,在这个task中,这个activity之上不能有其他的activity
if (top != null) {
if (top.frontOfTask) {
top.task.setIntent(r.intent, r.info);
}
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
r, top.task);
/// M: AMS log enhancement @{
if(!ActivityManagerService.IS_USER_BUILD)
Slog.d(TAG, "ACT-AM_NEW_INTENT " + r + top.task);
/// @}
top.deliverNewIntentLocked(callingUid, r.intent);
} else {

addingToTask = true;

sourceRecord = intentActivity;

}
}


//此时条件加上FLAG_ACTIVITY_NEW_TASK,且正要启动的Activity为root Activity,并且是在栈顶显示的
if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
&& intentActivity.realActivity.equals(r.realActivity)) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
intentActivity.task);
if (intentActivity.frontOfTask) {
intentActivity.task.setIntent(r.intent, r.info);
}
/// M: AMS log enhancement @{
if (!ActivityManagerService.IS_USER_BUILD)
Slog.d(TAG, "ACT-AM_NEW_INTENT " + r + intentActivity.task);
/// @}
intentActivity.deliverNewIntentLocked(callingUid, r.intent);
//判断要启动的Activity的包名是否为空,如果不为空的话,那么得到mHistory最顶部的ActivityRecord
//,接着判断当前顶部的Activity与要启动的Activity是否相同,并且Activity的进程以及ApplicationThread不为空
//,接着如果判断launchFlags为FLAG_ACTIVITY_SINGLE_TOP或者LaunchMode为SINGLE_TOP或者SINGLE_TASK的话,那么就调用resumeTopActivityLocked
//,并且调用top.deliverNewIntentLocked回调Activity的onNewIntent。否则如果包名为空,那么返回CLASS_NOT_FOUND结果。
} else if (!r.intent.filterEquals(intentActivity.task.intent)) {
// In this case we are launching the root activity
// of the task, but with a different intent.  We
// should start a new instance on top.
//我们要打开的app的初始界面不等于我们r.intent。即我们要新建r.intent的activity
addingToTask = true;
sourceRecord = intentActivity;

/// M: Add debug task message @{
if (DEBUG_TASKS) {
Slog.i(TAG, "since different intents, start new activity...");
}
/// @}
}


else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
// In this case an activity is being launched in to an
// existing task, without resetting that task.  This
// is typically the situation of launching an activity
// from a notification or shortcut.  We want to place
// the new activity on top of the current task.
addingToTask = true;
//addingToTask 如果为true表示正在添加至某个task
sourceRecord = intentActivity;
//在这种情况下只是把这个activity 移动到task顶部。并不重置这个task

/// M: Add debug task message @{
if (DEBUG_TASKS) {
Slog.i(TAG, "place the new activity on top of the current task...");
}
/// @}
} else if (!intentActivity.task.rootWasReset) {
// In this case we are launching in to an existing task
// that has not yet been started from its front door.
// The current task has been brought to the front.
// Ideally, we'd probably like to place this new task
// at the bottom of its stack, but that's a little hard
// to do with the current organization of the code so
// for now we'll just drop it.
intentActivity.task.setIntent(r.intent, r.info);
}


FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:

   一般与FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET结合使用,如果设置该属性,这个activity将在一个新的task中启动或者或者被带到一个已经存在的task的顶部,这时这个activity将会作为这个task的首个页面加载。将会导致与这个应用具有相同亲和力的task处于一个合适的状态(移动activity到这个task或者从中移出),或者简单的重置这个task到它的初始状态

   FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:在当前的Task堆栈中设置一个还原点,当带有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求启动这个堆栈时(典型的例子是用户从桌面再次启动这个应用),还原点之上包括这个应用将会被清除。应用场景:在email程序中预览图片时,会启动图片观览的actvity,当用户离开email处理其他事情,然后下次再次从home进入email时,我们呈现给用户的应该是上次email的会话,而不是图片观览,这样才不会给用户造成困惑。

例: 存在Activity A, Activity B, Activity C, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),

在Activity A中启动Activity B(TaskA堆栈状态: AB), 接着Activity B启动Activity C(TaskA堆栈状态: ABC),

启动Activity C的Intent中设置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET标题, 这样TaskA中有一个还原点,

当有包含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求TaskA堆栈时(比如请求Activity A)

系统就会将还原点以上的Activity清除, TaskA堆栈中只剩下了AB.

if (!addingToTask && reuseTask == null) {
//如果没有正在添加至某个Task, 并且不用加入一个已清除所有Activity的Task
//此时只需要显示栈顶Activity即可
if (doResume) {
targetStack.resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
}
/// M: Add debug task message @{
if (DEBUG_TASKS) {
Slog.i(TAG, "START_TASK_TO_FRONT, doResume = " + doResume);
}
/// @}
if (r.task == null)  Slog.v(TAG,
"startActivityUncheckedLocked: task left null",
new RuntimeException("here").fillInStackTrace());
return ActivityManager.START_TASK_TO_FRONT;
}
/// M: Fix ALPS01276300, reset mMovingToFront flag here @{
intentActivity.task.mMovingToFront = false;
/// @}


Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP

检查Intent是否设置了Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,这个标志我有点困惑,从它的注释可以看出它的含义是指如果设置了该flag,那么mHistory中最top的activity在后续的处理中将不被视为top,而将前一个activity视为top,如A–>B–>C,将B视为top。

这个top activity的作用很大,涉及到后面对task的处理。但是目前来看这个flag并没有起到该有的作用,代码中判断如果设置了该标志,那么AMS将会视当前正在启动的activity为top,然后去mHistory中去查找它的前一个activity为后续task处理的top activity(topRunningNonDelayedActivityLocked()中实现),但是现在的问题是此时此刻,正在启动的activity并不存在于mHistory中,因为我们在前一个函数中刚刚创建了这个ActivityRecord。如下面代码所示:

ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)

!= 0 ? r : null;

因此,感觉这个flag的意义不是太大。

if (r.packageName != null) {
ActivityStack topStack = getFocusedStack();
ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
if (top.app != null && top.app.thread != null) {//检测是否可复用Activity,top为Launcher,r为Setting,不满足
if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
top.task);
topStack.mLastPausedActivity = null;
if (doResume) {
resumeTopActivitiesLocked();
}
ActivityOptions.abort(options);
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {

if (r.task == null)  Slog.v(TAG,
"startActivityUncheckedLocked: task left null",
new RuntimeException("here").fillInStackTrace());
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
top.deliverNewIntentLocked(callingUid, r.intent);
//    当设置Intent.FLAG_ACTIVITY_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK这几种情况下,如果top activity与启动的activity为同一个activity,那么将复用top activity,并直接resume top activity
if (r.task == null)  Slog.v(TAG,
"startActivityUncheckedLocked: task left null",
new RuntimeException("here").fillInStackTrace());
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
}
}


else {

if (r.resultTo != null) {

r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,

r.requestCode, Activity.RESULT_CANCELED, null);

}

ActivityOptions.abort(options);

if (r.task == null) Slog.v(TAG,

“startActivityUncheckedLocked: task left null”,

new RuntimeException(“here”).fillInStackTrace());

return ActivityManager.START_CLASS_NOT_FOUND;//找不到包名所以取消

}



boolean newTask = false;
boolean keepCurTransition = false;

// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
targetStack = adjustStackFocus(r);//adjustStackFocus()获取目标stack。
moveHomeStack(targetStack.isHomeStack());
if (reuseTask == null) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
newTaskIntent != null ? newTaskIntent : intent,
true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
r.task);
} else {//如果reuse不为空,此时启动 c 会把 A B 清空
r.setTask(reuseTask, reuseTask, true);
}
newTask = true;


if (!movedHome) {
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity, so before starting
// their own activity we will bring home to the front.
r.task.mOnTopOfHome = true;
}
}


FLAG_ACTIVITY_TASK_ON_HOME :把当前新启动的任务置于Home任务之上,也就是按back键从这个任务返回的时候会回到home,即使这个不是他们最后看见的activity

注意这个标记必须和FLAG_ACTIVITY_NEW_TASK一起使用。

mOnTopOfHome的意思就是当我们按back键的时候发现mOnTopOfHome为true就返回到桌面。

} else if (sourceRecord != null) {//表示当前要启动的Activity和sourceRecord在同一个task中,因此不需要addingToTask =true
TaskRecord sourceTask = sourceRecord.task;
targetStack = sourceTask.stack;
moveHomeStack(targetStack.isHomeStack());
/// M: Fix ALPS01276300, need adjust task again since we may move home stack back here @{
mWindowManager.moveTaskToTop(targetStack.topTask().taskId);
/// @}
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing
// task, but the caller has asked to clear that task if the
// activity is already running.
ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
/// M: ALPS01265303, Fix google focused stack issue, performClearTaskLocked() may finish all activities in task.
/// If task is cleared and task.mOnTopOfHome is true, it will adjust focused stack to HomeStack.
/// We should adjust right focused task for WMS again. @{
if (r.task != null) {
mWindowManager.moveTaskToTop(r.task.taskId);
Slog.v(TAG, "WMS moveTaskToTop after AMS clear task, r = " + r + " task = " + r.task);
} else {
mWindowManager.moveTaskToTop(sourceTask.taskId);
Slog.v(TAG, "WMS moveTaskToTop after AMS clear task, r = " + r + " sourceTask = " + sourceTask);
}


addingToTask变量初始化为false,这个变量也将决定是否要将有关r的Activity在新的任务中启动,从名字我们就可以看出,默认不增加到原有的任务中启动,即要在新的任务中启动。

keepCurTransition = true;
if (top != null) {
top.setTask(sourceTask, sourceRecord.thumbHolder, false); //为该AactivityRecord设置一个新的TaskRecord
mService.setFocusedActivityLocked(top);
/// @}
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
/// M: AMS log enhancement @{
if(!ActivityManagerService.IS_USER_BUILD)
Slog.d(TAG, "ACT-AM_NEW_INTENT " + top + top.task);
/// @}
top.deliverNewIntentLocked(callingUid, r.intent);//重载要启动的的Activity,因为要启动的Activity在当前正在显示的task,所以可以使用此函数
// For paranoia, make sure we have correctly
// resumed the top activity.
targetStack.mLastPausedActivity = null;
//因为现在在启动新的Activity,没有需要暂停的Activity
if (doResume) {
targetStack.resumeTopActivityLocked(null);
}
ActivityOptions.abort(options);
if (r.task == null)  Slog.w(TAG,
"startActivityUncheckedLocked: task left null",
new RuntimeException("here").fillInStackTrace());
return ActivityManager.START_DELIVERED_TO_TOP;
}


else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
//如果已经启动了四个Activity:A,B,C和D,在D Activity里
//,想再启动一个Actvity B,但不变成A,B,C,D,B,而是希望是A,C,D,B
//,则可以像下面写代码:

//Intent intent = new Intent(this, MainActivity.class);
//intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
//startActivity(intent);

final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
if (top != null) {
final TaskRecord task = top.task;
task.moveActivityToFrontLocked(top);
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
/// M: AMS log enhancement @{
if(!ActivityManagerService.IS_USER_BUILD)
Slog.d(TAG, "ACT-AM_NEW_INTENT " + top + top.task);
/// @}
top.updateOptionsLocked(options);
top.deliverNewIntentLocked(callingUid, r.intent);
targetStack.mLastPausedActivity = null;
if (doResume) {
targetStack.resumeTopActivityLocked(null);
}
return ActivityManager.START_DELIVERED_TO_TOP;
}
r.setTask(sourceTask, sourceRecord.thumbHolder, false);//因为 sourceRecord不为空说明是task内部启动。所以r的task与sourceRecord一样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android