本系列博客將詳細闡述Activity的啟動流程。
深入理解Activity啟動流程(一)–Activity啟動的概要流程
深入理解Activity啟動流程(二)–Activity啟動相關類的類圖
深入理解Activity啟動流程(三)–Activity啟動的詳細流程1
深入理解Activity啟動流程(三)–Activity啟動的詳細流程2
前面兩篇博客介紹了Activity的詳細啟動流程,提到ActivityStack類的startActivityUncheckedLocked方法負責調(diào)度ActivityRecord和Task,并且調(diào)度算法非常復雜,需結合實際場景分析調(diào)度算法。本篇博客將介紹startActivityUncheckedLocked方法的具體實現(xiàn),本結合實際場景分析調(diào)度算法。
startActivityUncheckedLocked方法的具體實現(xiàn)
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//...
//如果從Launcher程序啟動應用,launchFlags為
//FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
//否則一般情況下launcheFlags為0,除非啟動Activity時設置了特殊的flag
int launchFlags = intent.getFlags();
//啟動Activity時默認不會設置FLAG_ACTIVITY_PREVIOUS_IS_TOP
//故此notTop默認情況下會是null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
//默認情況下startFlags不會設置START_FLAG_ONLY_IF_NEEDED
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//...默認情況下這里的代碼不會執(zhí)行
}
//根據(jù)被啟動的Activity和sourceRecord設置標志
//launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK
//如果從通知欄啟動應用 sourceRecord == null
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from non-Activity context;"
+"forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
+ intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
//一般情況下r.resultTo 不為null,它是啟動該Activity的Activity,
//如果從通知欄啟動Activity 則r.result為null
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...
r.resultTo = null;
}
//addingToTask 如果為true表示正在添加至某個task,
// 后續(xù)需要將r添加至sourceRecord所在的task
boolean addingToTask = false;
//movedHome表示是否移動home task
boolean movedHome = false;
//reuseTask 如果不為null,則表示已存在task,會重用這個task,
// 但是這個Task里的所有Activity會被清除掉,
// 需要將r加入這個task
TaskRecord reuseTask = null;
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) {
//從通知欄啟動時r.resultTo == null
//如果launchFlags設置了FLAG_ACTIVITY_NEW_TASK,r.resultTo也會為null
if (r.resultTo == null) {
//查找ActivityRecord棧,看要啟動的activity是否已有相關task,
//如果已經(jīng)有相關task,則不需要創(chuàng)建新的task,可以使用已有的task
//如果要啟動的activity的啟動模式是LAUNCH_SINGLE_INSTANCE,
//則使用快速查找方法findTaskLocked,否則使用慢速查找方法findActivityLocked
//因為如果啟動模式是LAUNCH_SINGLE_INSTANCE,則這個activity只會在一個單獨的Task里
//故此查找時,可以以task為單位進行查找和比較,這樣比較快
//查找得到的結果taskTop是相關task的棧頂?shù)腁ctivityRecord
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
//找到了相關task
if (taskTop != null) {
//重設task的intent
if (taskTop.task.intent == null) {
// This task was started because of movement of
// the activity based on affinity... now that we
// are actually launching it, we can assign the
// base intent.
taskTop.task.setIntent(intent, r.info);
}
//如果目標task不在棧頂,
//則先將Home task移動到棧頂(實際上只有當啟動Activity設置的Flag同時設置了
//FLAG_ACTIVITY_TASK_ON_HOME和FLAG_ACTIVITY_NEW_TASK才會移動home task,
//否則不會移動home task),
//然后再將目標task移動到棧頂
// If the target task is not in the front, then we need
// to bring it to the front... except... well, with
// SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
// to have the same behavior as if a new instance was
// being started, which means not bringing it to the front
// if the caller is not itself in the front.
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop != null && curTop.task != taskTop.task) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
boolean callerAtFront = sourceRecord == null
|| curTop.task == sourceRecord.task;
if (callerAtFront) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;
moveHomeToFrontFromLaunchLocked(launchFlags);
moveTaskToFrontLocked(taskTop.task, r, options);
options = null;
}
}
//如果launchFlags設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,則會重置task
//從Launcher應用程序啟動應用會設置FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
// If the caller has requested that the target task be
// reset, then do so.
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
taskTop = resetTaskIfNeededLocked(taskTop, r);
}
//... 一般情況下startFlags 不會設置 START_FLAG_ONLY_IF_NEEDED
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//...
}
// ==================================
//默認情況下不會設置 Intent.FLAG_ACTIVITY_CLEAR_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 = taskTop.task;
performClearTaskLocked(taskTop.task.taskId);
reuseTask.setIntent(r.intent, r.info);
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//默認情況下launchFlags不會設置FLAG_ACTIVITY_CLEAR_TOP
//但是如果被啟動的activity的啟動模式是singleTask或者singleInstance,
//也會進入該分支
// In this situation we want to remove all activities
// from the task up to the one being started. In most
// cases this means we are resetting the task to its
// initial state.
//清除r所在的task 在r之上的所有activity,
//該task里r和在r下的activity不會被清除
ActivityRecord top = performClearTaskLocked(
taskTop.task.taskId, r, launchFlags);
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different
// intents for the top activity, so make sure
// the task now has the identity of the new
// intent.
top.task.setIntent(r.intent, r.info);
}
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
} else {
// A special case: we need to
// start the activity because it is not currently
// running, and the caller has asked to clear the
// current task to have this activity at the top.
addingToTask = true;
// Now pretend like this activity is being started
// by the top of its task, so it is put in the
// right place.
sourceRecord = taskTop;
}
} else if (r.realActivity.equals(taskTop.task.realActivity)) {
// In this case the top activity on the task is the
// same as the one being launched, so we take that
// as a request to bring the task to the foreground.
// If the top activity in the task is the root
// activity, deliver this new intent to it if it
// desires.
if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
&& taskTop.realActivity.equals(r.realActivity)) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info);
}
taskTop.deliverNewIntentLocked(callingUid, r.intent);
} else if (!r.intent.filterEquals(taskTop.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.
addingToTask = true;
sourceRecord = taskTop;
}
} 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;
sourceRecord = taskTop;
} else if (!taskTop.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.
taskTop.task.setIntent(r.intent, r.info);
}
// ================================== end
//如果沒有正在添加至某個Task, 并且不用加入一個已清除所有Activity的Task
//此時只需要顯示棧頂Activity即可
if (!addingToTask && reuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client
// don't use that intent!) And for paranoia, make
// sure we have correctly resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
}
return ActivityManager.START_TASK_TO_FRONT;
}
}
}
}
//...
if (r.packageName != null) {
// If the activity being launched is the same as the one currently
// at the top, then we need to check if it should only be launched
// once.
ActivityRecord top = 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) {
if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//singleTop啟動模式或者singleTask啟動模式,
//并且task棧頂?shù)腶ctivity是要啟動的activity,則先顯示Activity
//然后調(diào)用該Activity的onNewIntent方法
logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
//先顯示Activity
if (doResume) {
resumeTopActivityLocked(null);
}
ActivityOptions.abort(options);
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!
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
//然后調(diào)用已顯示activity的onNewIntent方法
top.deliverNewIntentLocked(callingUid, r.intent);
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
}
}
} else {
if (r.resultTo != null) {
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
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) {
if (reuseTask == null) {
//創(chuàng)建新的task
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
//重復利用先前的task,該task里的所有acitivity已經(jīng)被清空
r.setTask(reuseTask, reuseTask, true);
}
newTask = true;
if (!movedHome) {
moveHomeToFrontFromLaunchLocked(launchFlags);
}
} else if (sourceRecord != null) {
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.
//清除r所在task在r之上的所有task,如果r不在task里,則返回的top為null
ActivityRecord top = performClearTaskLocked(
sourceRecord.task.taskId, r, launchFlags);
keepCurTransition = true;
if (top != null) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
//先調(diào)用onNewIntent方法 然后再顯示
top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null);
}
ActivityOptions.abort(options);
return ActivityManager.START_DELIVERED_TO_TOP;
}
} else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
//將棧里已有的activity移到棧頂
// In this case, we are launching an activity in our own task
// that may already be running somewhere in the history, and
// we want to shuffle it to the front of the stack if so.
int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
if (where >= 0) {
ActivityRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.updateOptionsLocked(options);
top.deliverNewIntentLocked(callingUid, r.intent);
if (doResume) {
resumeTopActivityLocked(null);
}
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
// An existing activity is starting this new activity, so we want
// to keep the new one in the same task as the one that is starting
// it.
//同一個應用程序里的Activity A和Activity B,A可跳轉至B,沒有設置taskAffinity
//B的啟動模式為singleTask,從A跳轉至B時,B和A會在同一個task里
//該情況下會執(zhí)行到這里的代碼,將B的task設置為和A一樣的task
r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
// This not being started from an existing activity, and not part
// of a new task... just put it in the top task, though these days
// this case should never happen.
final int N = mHistory.size();
ActivityRecord prev =
N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
: new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r.getUriPermissionsLocked());
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
}
logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
return ActivityManager.START_SUCCESS;
}
實際場景分析
實際場景1:
應用內(nèi)有兩個Activity,A和B,A為第應用入口Activity,從A可跳轉至B,A和B的啟動模式都為standard
1)從Launcher程序第1次啟動應用時的任務調(diào)度情況:
任務調(diào)度時會創(chuàng)建新task并將新的ActivityRecord加入這個新的task
2)然后跳轉至應用內(nèi)Activity時的任務調(diào)度情況:
任務調(diào)度時會將新的ActivityRecord加入已有的task
3)然后按Home鍵,再打開應用程序時的調(diào)度情況:
任務調(diào)度時會先找到已有的相關task,并顯示棧頂?shù)腁ctivity
1)從Launcher程序第1次啟動應用時
會創(chuàng)建新task并將新的ActivityRecord加入這個新的task,任務調(diào)度執(zhí)行如下所示:
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//...
//launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
int launchFlags = intent.getFlags();
//...
//沒設置FLAG_ACTIVITY_PREVIOUS_IS_TOP,故此notTop為null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
//startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
//...
//sourceRecord為Launcher應用的Activity launcher應用activity的啟動模式為singleTask
// 故此下面的3個條件分支的內(nèi)容都不會執(zhí)行
if (sourceRecord == null) {
//...
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//...
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//...
}
//...
//r.resultTo不為null, launchFlags設置了FLAG_ACTIVITY_NEW_TASK,需要將r.resultTo置為null
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...
r.resultTo = null;
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
//因為launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
//故此下面的條件會滿足, 也就是說只要從Launcher程序啟動應用,下面這個條件肯定會滿足
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,taskTop則為null
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
//... 這里面的內(nèi)容不會執(zhí)行
}
}
}
//...
//r.packageName != null
if (r.packageName != null) {
//如果被啟動的Activity正好是棧頂?shù)腁ctivity,
//并且被啟動的Activity啟動模式是singleTop或者singleTask,
//則不用將新的ActivityRecord加入到棧里
//top Activity為Launcher應用的Activity
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
//top.realActivity.equals(r.realActivity)不滿足
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
//... 這里的代碼不會被執(zhí)行
}
}
} else {
//...
}
boolean newTask = false;
boolean keepCurTransition = false;
// 此時 r.resultTo為null addingToTask為false launchFlags設置了FLAG_ACTIVITY_NEW_TASK
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (reuseTask == null) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
//創(chuàng)建新task
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
//...這里的代碼會執(zhí)行
}
newTask = true;
if (!movedHome) {
moveHomeToFrontFromLaunchLocked(launchFlags);
}
} else if (sourceRecord != null) {
//... 這里的代碼不會被執(zhí)行
} else {
//...這里的代碼不會被執(zhí)行
}
//...
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
return ActivityManager.START_SUCCESS;
}
2)跳轉至應用內(nèi)Activity時
會將新的ActivityRecord加入已有的task,任務調(diào)度執(zhí)行如下所示:
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//此時launchFlags為0
int launchFlags = intent.getFlags();
//notTop為null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
//startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
//...
if (sourceRecord == null) {
//...這里的代碼不會被執(zhí)行
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//...這里的代碼不會被執(zhí)行
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//...這里的代碼不會被執(zhí)行
}
//r.resultTo != null 但是launchFlags未設置FLAG_ACTIVITY_NEW_TASK
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//... 這里的代碼不執(zhí)行
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
//launchFlags為0 r的啟動模式為standard 故此下面的邏輯都不會執(zhí)行
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) {
//... 這里的代碼不執(zhí)行
}
//...
if (r.packageName != null) {
//top 是ActivityA 的ActivityRecord,
//但是被啟動的Activity和top不是同一個Activity
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
//...這里的代碼不執(zhí)行
}
}
} else {
//...這里的代碼不執(zhí)行
}
boolean newTask = false;
boolean keepCurTransition = false;
//此時 r.resultTo !=null sourceRecord != null addingToTask=false
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...這里的代碼不執(zhí)行
} else if (sourceRecord != null) {
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
//... 這里的代碼不執(zhí)行
} else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
//... 這里的代碼不執(zhí)行
}
//添加到現(xiàn)有的task
r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
//...
} else {
//... 這里的代碼不執(zhí)行
}
//...
return ActivityManager.START_SUCCESS;
}
3)然后按Home鍵,再打開應用程序
此時會先找到已有的相關task,并顯示棧頂?shù)腁ctivity,任務調(diào)度執(zhí)行如下所示:
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//...
//launchFlags為FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
int launchFlags = intent.getFlags();
//notTop為null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
//startFlags未設置ActivityManager.START_FLAG_ONLY_IF_NEEDED
//...
if (sourceRecord == null) {
//...這里的代碼不會被執(zhí)行
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//...這里的代碼不會被執(zhí)行
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//...這里的代碼不會被執(zhí)行
}
//此時 r.resultTo != null launchFlags設置了FLAG_ACTIVITY_NEW_TASK
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...
r.resultTo = null;
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
//此時launchFlags設置了FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
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) {
//此時 r.resultTo == null
if (r.resultTo == null) {
//此時已有相關task,并且task 棧的棧頂是Activity B的ActivityRecord
//故此taskTop為Activity B的ActivityRecord
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
//...
// 此時curTop是Launcher應用的Activity的ActivityRecord
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop != null && curTop.task != taskTop.task) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//此時Launcher應用的task在棧頂,故此callerAtFront為true,
//此時會把被啟動的應用的task移至棧頂
boolean callerAtFront = sourceRecord == null
|| curTop.task == sourceRecord.task;
if (callerAtFront) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;
moveHomeToFrontFromLaunchLocked(launchFlags);
moveTaskToFrontLocked(taskTop.task, r, options);
options = null;
}
}
//此時launchFlags設置了FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
//此時需要重置task 重置完后 taskTop為ActivityB的ActivityRecord
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
taskTop = resetTaskIfNeededLocked(taskTop, r);
}
//startFlags為0
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//... 這些代碼都不會被執(zhí)行
}
//根據(jù)launchFlags和被啟動的activity的信息 設置resueTask addingTask變量的值
//沒設置 Intent.FLAG_ACTIVITY_CLEAR_TASK
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
//... 這些代碼都不會被執(zhí)行
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//... 這些代碼都不會被執(zhí)行
} else if (r.realActivity.equals(taskTop.task.realActivity)) {
//... 這些代碼都不會被執(zhí)行
} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
//因為從Launcher程序啟動時launchFlags設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
//所以不會進入該分支
//... 這些代碼都不會被執(zhí)行
} else if (!taskTop.task.rootWasReset) {
//... 這些代碼都不會被執(zhí)行
}
//此時addingToTask為false,reuseTask為null,故此顯示棧頂Actvity即可
if (!addingToTask && reuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client
// don't use that intent!) And for paranoia, make
// sure we have correctly resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
}
return ActivityManager.START_TASK_TO_FRONT;
}
}
}
}
//... 以下代碼都不會被執(zhí)行
}
實際場景2:
應用內(nèi)有兩個Activity,A和B,A為第應用入口Activity,從A可跳轉至B,A的啟動模式都為standard,B的啟動模式為singleTop
此時已從Launchenr程序打開應用,啟動了Actvity A,再從A跳轉至B,此時的任務調(diào)度情況:
此時不會創(chuàng)建新的Task,而是將B的ActivityRecord加入到A所在的task里
任務調(diào)度執(zhí)行如下所示:
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//...
//此時launcheFlags為0
int launchFlags = intent.getFlags();
//notTop為null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
//默認情況下startFlags不會設置START_FLAG_ONLY_IF_NEEDED
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//...這里的代碼不會執(zhí)行
}
//r.launchMode = ActivityInfo.LAUNCH_SINGLE_TASK
if (sourceRecord == null) {
//這里的代碼不會執(zhí)行
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
//這里的代碼不會執(zhí)行
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
//此時r.resultTo!=null launchFlags設置了Intent.FLAG_ACTIVITY_NEW_TASK
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...
r.resultTo = null;
}
//addingToTask如果為true表示正在添加至某個task,后續(xù)需要將r添加至sourceRecord所在的task
boolean addingToTask = false;
//movedHome表示是否移動home task
boolean movedHome = false;
TaskRecord reuseTask = null;
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) {
//此時 r.resultTo = null
if (r.resultTo == null) {
//此時找到的taskTop是Activity A的ActivityRecord,
//因為Actvity B和A的ActivityRecord所在的Task是相關的
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
//找到了相關task
if (taskTop != null) {
//重設task的intent
if (taskTop.task.intent == null) {
//...
}
//此時找到的task已在棧頂
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop != null && curTop.task != taskTop.task) {
//... 這里的代碼不會執(zhí)行
}
//launchFlags為0
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
taskTop = resetTaskIfNeededLocked(taskTop, r);
}
//... 一般情況下startFlags 不會設置 START_FLAG_ONLY_IF_NEEDED
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
//...
}
// ==================== begin
// launchFlags此時為0
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
//...這里的代碼不執(zhí)行
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
// 故此會進入該分支
//因為B還從未啟動,故此得到的top為null
ActivityRecord top = performClearTaskLocked(
taskTop.task.taskId, r, launchFlags);
if (top != null) {
//...這里的代碼不執(zhí)行
} else {
addingToTask = true;
sourceRecord = taskTop;
}
} else if (r.realActivity.equals(taskTop.task.realActivity)) {
//...這里的代碼不執(zhí)行
} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
//...這里的代碼不執(zhí)行
} else if (!taskTop.task.rootWasReset) {
//...這里的代碼不執(zhí)行
}
// ==================== end
// 此時 addingToTask為true
if (!addingToTask && reuseTask == null) {
//...這里的代碼不執(zhí)行
}
}
}
}
//...
if (r.packageName != null) {
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
//此時task還沒有B的ActivityRecord,故此不會進入下述分支
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
//...這里的代碼不執(zhí)行
}
}
} else {
//...這里的代碼不執(zhí)行
}
boolean newTask = false;
boolean keepCurTransition = false;
// 此時 r.resultTo == null addingToTask為true sourceRecord != null
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
//...這里的代碼不執(zhí)行
} else if (sourceRecord != null) {
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
//...這里的代碼不執(zhí)行
} else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
//...這里的代碼不執(zhí)行
}
//將B的ActivityRecord加入A的ActivityRecord所在的Task里
r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
//...
} else {
//...這里的代碼不執(zhí)行
}
//...
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
return ActivityManager.START_SUCCESS;
}
總結
從上面的分析可以看出來,Activity和Task的調(diào)度算法非常復雜,需結合實際場景才好分析,只有這樣才知道是否需要新建Task,還是將新的ActivityRecord加入到已有的Task里,不過我們?nèi)绻芾斫鈫幽J降囊恍┨攸c,對理解調(diào)度算法會有很大幫助。
大家可以結合下述場景分析調(diào)度算法:
1.從通知欄啟動Activity:
假設應用有Activity A ,Activity A已啟動,
此時發(fā)了一個通知,該通知用于啟動Activity A,啟動Activity A時不加任何特殊flag
點擊通知,針對以下情況對任務調(diào)度情況進行分析:
Activity A的啟動模式為standard
Activity A的啟動模式為singleTop
Activity A的啟動模式為singleTask
Activity A的啟動模式為singleInstance
2.跨應用跳轉Activity
假設應用app1有一個Activity A,另一個應用app2有一個Activity B
Activity A可跳轉至Activity B
因為Activity A和Actiivty B在不同應用,所以Activity的taskffinity必然不同
現(xiàn)在Activity A已啟動,跳轉至Activity B,
針對以下4種情況分析跳轉之后的Activity Task情況
Activity B的啟動模式為standard
Activity B的啟動模式為singleTop
Activity B的啟動模式為singleTask
Activity B的啟動模式為singleInstance
如果大家對上述場景分析有興趣的話,可以在評論里一起探討結果。