Android應(yīng)用程序組件Activity的"singleTask"(6)
現(xiàn)在,我們?nèi)绾蝸?lái)確認(rèn)SubActivity是不是在新的任務(wù)中啟動(dòng)并且位于這個(gè)新任務(wù)的堆棧底部呢?
Android源代碼工程為我們準(zhǔn)備了adb工具。
可以查看模擬器上系統(tǒng)運(yùn)行的狀況。
執(zhí)行下面的命令查看:
- [html] view plaincopyUSER-NAME@MACHINE-NAME:~/Android$ adb shell dumpsys
 - tivity
 - 這個(gè)命令輸出的內(nèi)容比較多,這里我們只關(guān)心TaskRecord部分:[html] view plaincopyRunning activities
 - ost recent first):
 - TaskRecord{4070d8f8 #3 A shy.luo.task}
 - Run #2: HistoryRecord{406a13f8 shy.luo.task/.SubActivity}
 - Run #1: HistoryRecord{406a0e00 shy.luo.task/.MainActivity}
 - TaskRecord{4067a510 #2 A com.android.launcher}
 - Run #0: HistoryRecord{40677518
 - m.android.launcher/com.android.launcher2.Launcher}
 
果然,SubActivity和MainActivity都是運(yùn)行在TaskRecord#3中,并且SubActivity在MainActivity 的上面。這是怎么回事呢?碰到這種情況,Linus Torvalds告誡我們:Read the fucking source code;去年張麻子又說(shuō):槍在手,跟我走;我們沒(méi)有槍,但是有source code,因此,我要說(shuō):跟著代碼走。
前面我們?cè)趦善恼翧ndroid應(yīng)用程序啟動(dòng)過(guò)程源代碼分析和Android應(yīng)用程序內(nèi)部啟動(dòng)Activity過(guò)程(startActivity) 的源代碼分析時(shí),分別在Step 9和Step 8中分析了Activity在啟動(dòng)過(guò)程中與任務(wù)相關(guān)的函數(shù)ActivityStack.startActivityUncheckedLocked函數(shù) 中,它定義在frameworks/base/services/java/com/android/server/am /ActivityStack.java文件中:
- [java] view plaincopypublic class ActivityStack {
 - ......
 - final int startActivityUncheckedLocked(ActivityRecord r,
 - ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
 - int grantedMode, boolean onlyIfNeeded, boolean doResume) {
 - final Intent intent = r.intent;
 - final int callingUid = r.launchedFromUid;
 - int launchFlags = intent.getFlags();
 - ......
 - ActivityRecord notTop =
 - (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
 - != 0 ? r : null;
 - ......
 - 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) {
 - // The activity being started is a single instance... it always
 - // gets launched into its own task.
 - launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
 - }
 - ......
 - boolean addingToTask = false;
 - 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 bring to front is requested, and no result is requested, and
 - // we can find a task that was started with this same
 - // component, then instead of launching bring that one to the front.
 - if (r.resultTo == null) {
 - // 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);
 - if (taskTop != null) {
 - ......
 - if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
 - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
 - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
 - // 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.
 - ActivityRecord top = performClearTaskLocked(
 - taskTop.task.taskId, r, launchFlags, true);
 - if (top != null) {
 - ......
 - } 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)) {
 - ......
 - } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) ==
 - 0) {
 - ......
 - } else if (!taskTop.task.rootWasReset) {
 - ......
 - }
 - ......
 - }
 - }
 - }
 - ......
 - 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)) {
 - if (top.app != null && top.app.thread != null) {
 - ......
 - }
 - }
 - }
 - } else {
 - ......
 - }
 - boolean newTask = false;
 - // Should this be considered a new task?
 - if (r.resultTo == null && !addingToTask
 - && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
 - // todo: should do better management of integers.
 - mService.mCurTask++;
 - if (mService.mCurTask <= 0) {
 - mService.mCurTask = 1;
 - }
 - r.task = new TaskRecord(mService.mCurTask, r.info, intent,
 - (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
 - if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
 - + " in new task " + r.task);
 - newTask = true;
 - if (mMainStack) {
 - mService.addRecentTaskLocked(r.task);
 - }
 - } else if (sourceRecord != null) {
 - if (!addingToTask &&
 - (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
 - ......
 - } else if (!addingToTask &&
 - (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
 - ......
 - }
 - // 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.
 - r.task = sourceRecord.task;
 - ......
 - } else {
 - ......
 - }
 - ......
 - startActivityLocked(r, newTask, doResume);
 - return START_SUCCESS;
 - }
 - ......
 - }
 















 
 
 
 
 
 
 