Activity LaunchMode源碼分析

之前一篇文章分析了Android Activity啟動(dòng)過程源碼 這里單獨(dú)拿出來(lái)一篇文章分析Activity 啟動(dòng)模式的源碼

我們知道Activity的start是走到Instrumentation的execStartActivity方法中盏阶,而這里是調(diào)用了ActivityManagerNative的getDefault方法 來(lái)獲得一個(gè)ActivityManagerService(以下簡(jiǎn)稱AMS)的遠(yuǎn)程代理對(duì)象,要走到AMS的startActivity方法。

        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, null, options);
        checkStartActivityResult(result, intent);

這里先解釋一下startActivity方法里的一些參數(shù)

參數(shù) 作用
whoThread IApplicationThread的binder對(duì)象 用于AMS進(jìn)行進(jìn)程間通信
who 上下文對(duì)象 其實(shí)就是Activity
intent 目標(biāo)intent
intent.resolveTypeIfneed 若沒有在Manifest文件里面注明Activity的mime類型,返回null
token Binder對(duì)象 通過它可以獲得Activity的相關(guān)信息 后邊會(huì)保存到sourceRecord這個(gè)對(duì)象里面
target 我們調(diào)用的Activity
requestCode 若沒有設(shè)置結(jié)果就是小于0
0 flags
ProfilerInfo null
options 是一個(gè)bunder對(duì)象肩祥,記錄用intent傳遞的信息

這里對(duì)應(yīng)著AMS 中startactivity的參數(shù)

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }
    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, userId, null, null);
    }

然后會(huì)調(diào)用ActivityStackSupervisor的startActivityMayWait方法
而ActivityStackSupervisor 就是專門管理activity的堆棧的類

startActivityMayWait

這里會(huì)先解析我們的intent來(lái)獲取信息佑惠,通過調(diào)用函數(shù)resoleActivity方法獲取ActivityInfo,這里主要是activity在AndroidManifest.xml里的信息

再往下看葛假,進(jìn)入到startActivityLocked 方法中

另提一下activity 在 AMS 中的形式是 ActivityRecord,task 在 AMS 中的形式為TaskRecord,進(jìn)程在 AMS 中的管理形式為 ProcessRecord

我們發(fā)現(xiàn)這里有兩個(gè)ActivityRecord對(duì)象 有sourceRecord 和resultRecord

sourceRecord 代表的是最開始的activity
這就是通過resultTo這個(gè)binder對(duì)象獲得Mainactivity的相關(guān)信息然后保存到這個(gè)對(duì)象中
resultRecord 代表的是接受啟動(dòng)結(jié)果的Activity
因?yàn)閞equestcode==-1 所以這里resultRecord==null

final int launchFlags = intent.getFlags();
這里獲取Intent的啟動(dòng)Flag 就是我們?cè)贗ntent.setFlag里面設(shè)置的標(biāo)志
這個(gè)函數(shù)的主要作用就是處理sourceRecord和resultRecord兩個(gè)對(duì)象
在這里sourceRecord和resultRecord指向的應(yīng)該是同一個(gè)activity

然后調(diào)用startActivityUncheckedLocked來(lái)處理本次的啟動(dòng)Activity的請(qǐng)求


startActivityUncheckedLocked

從這里我們可以看到 獲取了activity的launchModel 情竹,也就是對(duì)launchModel的判斷處理應(yīng)該是在這里
這里先判斷是否FLAG_ACTIVITY_NEW_DOCUMENT藐不,這個(gè)平時(shí)用的比較少,在android5.0上主要是決定你的task和activity是如何展現(xiàn)在overview screen 中的秦效,詳細(xì)請(qǐng)看Android 5.0 Overview Screen--總覽畫面
再往下看


startFlags == 0 所以此時(shí)不會(huì)進(jìn)入這個(gè)判斷雏蛮,沒有設(shè)置這個(gè)FLAG_ACTIVITY_PREVIOUS_IS_TOP,所以我們的notTop==null
接著 系統(tǒng)默認(rèn)addingToTask= false 默認(rèn)是開啟新的Task阱州,從后面的判斷也可以看出來(lái)


之前說過 sourceRecord就是最開始的activity 所以它不會(huì)為null挑秉,這樣就到了else 中 inTask = null;

在這里判斷了啟動(dòng)模式苔货,判斷當(dāng)前activity的啟動(dòng)模式和要啟動(dòng)的activity的啟動(dòng)模式犀概,根據(jù)相應(yīng)的啟動(dòng)模式設(shè)置launchFlags

這里目的是判斷啟動(dòng)的activity是否在堆棧里存在,如果存在就直接在進(jìn)行相應(yīng)的操作
在文章開頭 resultRecord 默認(rèn)為null而且requestCode假如沒有設(shè)置的話夜惭,requestCode小于0姻灶,所以resultRecord沒有被賦值,所以我們構(gòu)造ActivityRecord 時(shí)傳入的是null滥嘴,也就是可以進(jìn)入這個(gè)if判斷里
再往里看


這里會(huì)判斷啟動(dòng)的activity是否是SingleInstance木蹬,根據(jù)此進(jìn)入不同的方法,目的是找到activity若皱,如果有就返回镊叁,如果沒有就返回null,先來(lái)看findTaskLocked方法

findTaskLocked

stack里的findTaskLocked方法比較長(zhǎng)走触,頂部activity晦譬,如果沒有就返回null,從注釋上來(lái)看就是返回堆棧里的activity,簡(jiǎn)單說一下就是返回發(fā)起請(qǐng)求的activity互广,也是這個(gè)函數(shù)返回的activity

    /**
     * Returns the top activity in any existing task matching the given
     * Intent.  Returns null if no such task is found.
     */
    ActivityRecord findTaskLocked(ActivityRecord target) {
        Intent intent = target.intent;
        ActivityInfo info = target.info;
        ComponentName cls = intent.getComponent();
        if (info.targetActivity != null) {
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
        boolean isDocument = intent != null & intent.isDocument();
        // If documentData is non-null then it must match the existing task data.
        Uri documentData = isDocument ? intent.getData() : null;

        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            final TaskRecord task = mTaskHistory.get(taskNdx);
            if (task.voiceSession != null) {
                // We never match voice sessions; those always run independently.
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
                continue;
            }
            if (task.userId != userId) {
                // Looking for a different task.
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
                continue;
            }
            final ActivityRecord r = task.getTopActivity();
            if (r == null || r.finishing || r.userId != userId ||
                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": mismatch root " + r);
                continue;
            }

            final Intent taskIntent = task.intent;
            final Intent affinityIntent = task.affinityIntent;
            final boolean taskIsDocument;
            final Uri taskDocumentData;
            if (taskIntent != null && taskIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = taskIntent.getData();
            } else if (affinityIntent != null && affinityIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = affinityIntent.getData();
            } else {
                taskIsDocument = false;
                taskDocumentData = null;
            }

            if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
                    + taskIntent.getComponent().flattenToShortString()
                    + "/aff=" + r.task.rootAffinity + " to new cls="
                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
            if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
                    return r;
                }
            } else if (taskIntent != null && taskIntent.getComponent() != null &&
                    taskIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
                        + r.intent);
                return r;
            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                    affinityIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
                        + r.intent);
                return r;
            } else if (DEBUG_TASKS) {
                Slog.d(TAG, "Not a match: " + task);
            }
        }
    return null;
}

這里簡(jiǎn)單說一下敛腌,先是從mTaskHistory中遍歷得到一個(gè)任務(wù)Task,并根據(jù)userid找到當(dāng)前的task 惫皱,找到這個(gè)任務(wù)的頂部activity像樊,并且保證它啟動(dòng)模式不是singleInstance,都滿足了返回以下條件的activity

再回到剛才的方法往下看


這里先去activitystack里的moveToFront()方法

                    // 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) {
                            resumeTopActivitiesLocked(targetStack, null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    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();
                        reuseTask.setIntent(r);
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                            || launchSingleInstance || launchSingleTask) {
                        // 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 =
                                intentActivity.task.performClearTaskLocked(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);
                            }
                            ActivityStack.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 = intentActivity;
                        }
                    } else if (r.realActivity.equals(intentActivity.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 || launchSingleTop)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                                    intentActivity.task);
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r);
                            }
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
                        } 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.
                            addingToTask = true;
                            sourceRecord = intentActivity;
                        }
                    } 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 = intentActivity;
                    } 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);
                    }
                    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) {
                            targetStack.resumeTopActivityLocked(null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_TASK_TO_FRONT;
                    }

這里主要看

這里走到了ActivityStack的performClearTaskLocked方法里

 /**
     * Perform clear operation as requested by
     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
     * stack to the given task, then look for
     * an instance of that activity in the stack and, if found, finish all
     * activities on top of it and return the instance.
     *
     * @param newR Description of the new activity being started.
     * @return Returns the old activity that should be continued to be used,
     * or null if none was found.
     */
    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
        int numActivities = mActivities.size();
        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
            ActivityRecord r = mActivities.get(activityNdx);
            if (r.finishing) {
                continue;
            }
            if (r.realActivity.equals(newR.realActivity)) {
                // Here it is!  Now finish everything in front...
                final ActivityRecord ret = r;

                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
                    r = mActivities.get(activityNdx);
                    if (r.finishing) {
                        continue;
                    }
                    ActivityOptions opts = r.takeOptionsLocked();
                    if (opts != null) {
                        ret.updateOptionsLocked(opts);
                    }
                    if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
                            false)) {
                        --activityNdx;
                        --numActivities;
                    }
                }

                // Finally, if this is a normal launch mode (that is, not
                // expecting onNewIntent()), then we will finish the current
                // instance of the activity so a new fresh one can be started.
                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                    if (!ret.finishing) {
                        stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
                                "clear", false);
                        return null;
                    }
                }

                return ret;
            }
        }

        return null;
    }

這里就是根據(jù)ID找到等于參數(shù)taskId的任務(wù)旅敷,然后在這個(gè)任務(wù)中查找是否已經(jīng)存在即將要啟動(dòng)的Activity的實(shí)例生棍,如果存在,就會(huì)把這個(gè)Actvity實(shí)例上面直到任務(wù)堆棧頂端的Activity通過調(diào)用finishActivityLocked函數(shù)將它們結(jié)束掉媳谁。

在這里便引出了manifest文件中<activity>的一個(gè)重要屬性涂滴,taskAffinity。在官方文檔中可以得到關(guān)于taskAffinity的以下信息

  • taskAffinity表示當(dāng)前activity具有親和力的一個(gè)任務(wù)(原句為The task that the activity has an affinity for.)晴音,大致可以這樣理解柔纵,這個(gè) taskAffinity表示一個(gè)任務(wù),這個(gè)任務(wù)就是當(dāng)前activity所在的任務(wù)锤躁。
    在概念上搁料,具有相同的affinity的activity(即設(shè)置了相同taskAffinity屬性的activity)屬于同一個(gè)任務(wù)。
  • 一個(gè)任務(wù)的affinity決定于這個(gè)任務(wù)的根activity(root activity)的taskAffinity系羞。
  • 這個(gè)屬性決定兩件事:當(dāng)activity被re-parent時(shí)加缘,它可以被re-paren哪個(gè)任務(wù)中;當(dāng)activity以FLAG_ACTIVITY_NEW_TASK標(biāo)志啟動(dòng)時(shí)觉啊,它會(huì)被啟動(dòng)到哪個(gè)任務(wù)中拣宏。(這個(gè)比較 難以理解,請(qǐng)結(jié)合<activity>中的屬性allowTaskReparenting和Intent中的標(biāo)志 FLAG_ACTIVITY_NEW_TASK加以理解)
  • 默認(rèn)情況下杠人,一個(gè)應(yīng)用中的所有activity具有相同的taskAffinity勋乾,即應(yīng)用程序的包名。我們可以通過設(shè)置不同的taskAffinity屬性給應(yīng)用中的activity分組嗡善,也可以把不同的 應(yīng)用中的activity的taskAffinity設(shè)置成相同的值辑莫。
    為一個(gè)activity的taskAffinity設(shè)置一個(gè)空字符串,表明這個(gè)activity不屬于任何task罩引。

回到前面的startActivityUncheckedLocked函數(shù)中各吨,這里的變量top就為null了,于是執(zhí)行下面的else語(yǔ)句

所以 此時(shí)將addintToTask=true 并且sourceRecord = 我們的activity袁铐,再往下看

        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.
            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) {
                        if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || launchSingleTop || launchSingleTask) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                    top.task);
                            // For paranoia, make sure we have correctly
                            // resumed the top activity.
                            topStack.mLastPausedActivity = null;
                            if (doResume) {
                                resumeTopActivitiesLocked();
                            }
                            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;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent);
                            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);
            return ActivityManager.START_CLASS_NOT_FOUND;
        }

根據(jù)注釋我們能看出這個(gè)方法是檢查當(dāng)前任務(wù)的頂端是否是我們要啟動(dòng)的activity揭蜒,接著往下看横浑,便是啟動(dòng)activity

        boolean newTask = false;
        boolean keepCurTransition = false;

        TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
                sourceRecord.task : null;

        // Should this be considered a new task?
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            if (isLockTaskModeViolation(reuseTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            newTask = true;
            targetStack = adjustStackFocus(r, newTask);
            if (!launchTaskBehind) {
                targetStack.moveToFront();
            }
            if (reuseTask == null) {
                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                        taskToAffiliate);
                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                        r.task);
            } else {
                r.setTask(reuseTask, taskToAffiliate);
            }
            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.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                }
            }
        } else if (sourceRecord != null) {
            final TaskRecord sourceTask = sourceRecord.task;
            if (isLockTaskModeViolation(sourceTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            targetStack = sourceTask.stack;
            targetStack.moveToFront();
            final TaskRecord topTask = targetStack.topTask();
            if (topTask != sourceTask) {
                targetStack.moveTaskToFrontLocked(sourceTask, r, options);
            } else {
                mWindowManager.moveTaskToTop(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);
                keepCurTransition = true;
                if (top != null) {
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    // For paranoia, make sure we have correctly
                    // resumed the top activity.
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.resumeTopActivityLocked(null);
                    }
                    ActivityOptions.abort(options);
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            } else if (!addingToTask &&
                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
                // 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.
                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);
                    top.updateOptionsLocked(options);
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.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.
            r.setTask(sourceTask, null);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in existing task " + r.task + " from source " + sourceRecord);

        } else if (inTask != null) {
            // The calling is asking that the new activity be started in an explicit
            // task it has provided to us.
            if (isLockTaskModeViolation(inTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            targetStack = inTask.stack;
            targetStack.moveTaskToFrontLocked(inTask, r, options);
            targetStack.moveToFront();
            mWindowManager.moveTaskToTop(inTask.taskId);

            // Check whether we should actually launch the new activity in to the task,
            // or just reuse the current activity on top.
            ActivityRecord top = inTask.getTopActivity();
            if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                        || launchSingleTop || launchSingleTask) {
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
                    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;
                    }
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            }

            if (!addingToTask) {
                // We don't actually want to have this activity added to the task, so just
                // stop here but still tell the caller that we consumed the intent.
                ActivityOptions.abort(options);
                return ActivityManager.START_TASK_TO_FRONT;
            }

            r.setTask(inTask, null);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in explicit 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.
            targetStack = adjustStackFocus(r, newTask);
            targetStack.moveToFront();
            ActivityRecord prev = targetStack.topActivity();
            r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                            r.info, intent, null, null, true), null);
            mWindowManager.moveTaskToTop(r.task.taskId);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new guessed " + r.task);
        }

        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
                intent, r.getUriPermissionsLocked(), r.userId);

        if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
            r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
        }
        if (newTask) {
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
        }
        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
        targetStack.mLastPausedActivity = null;
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
        if (!launchTaskBehind) {
            // Don't set focus on an activity that's going to the back.
            mService.setFocusedActivityLocked(r);
        }
        return ActivityManager.START_SUCCESS;
    }

首先將newTask變量初始化為false,表示不要在新的任務(wù)中啟動(dòng)Activity屉更。由于前面的已經(jīng)把a(bǔ)ddingToTask設(shè)置為true徙融,因此,這里會(huì)執(zhí)行中間的else if語(yǔ)句瑰谜,即這里會(huì)把r.task設(shè)置為sourceRecord.task欺冀,即把即將啟動(dòng)的Activity放在原Activity所在的任務(wù)中啟動(dòng)。最后萨脑,就是調(diào)用startActivityLocked函數(shù)繼續(xù)進(jìn)行啟動(dòng)Activity的操作了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隐轩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子渤早,更是在濱河造成了極大的恐慌职车,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛛芥,死亡現(xiàn)場(chǎng)離奇詭異提鸟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)仅淑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門称勋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人涯竟,你說我怎么就攤上這事赡鲜。” “怎么了庐船?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵银酬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我筐钟,道長(zhǎng)揩瞪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任篓冲,我火速辦了婚禮李破,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壹将。我一直安慰自己嗤攻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布诽俯。 她就那樣靜靜地躺著妇菱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闯团,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天辛臊,我揣著相機(jī)與錄音,去河邊找鬼偷俭。 笑死浪讳,一個(gè)胖子當(dāng)著我的面吹牛缰盏,可吹牛的內(nèi)容都是我干的涌萤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼口猜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼负溪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起济炎,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤川抡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后须尚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崖堤,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年耐床,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了密幔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撩轰,死狀恐怖胯甩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堪嫂,我是刑警寧澤偎箫,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站皆串,受9級(jí)特大地震影響淹办,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恶复,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一怜森、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寂玲,春花似錦塔插、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春流纹,著一層夾襖步出監(jiān)牢的瞬間糜烹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工漱凝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疮蹦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓茸炒,卻偏偏與公主長(zhǎng)得像愕乎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壁公,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容