ActivityManagerService-C 管理場(chǎng)景分析

版權(quán)說(shuō)明:本文為 開開向前沖 記錄文章,轉(zhuǎn)載請(qǐng)注明出處;
注:限于作者水平有限,文中有不對(duì)的地方還請(qǐng)指教

在文章ActivityManagerService-A中對(duì)AMS 中核心的幾個(gè)數(shù)據(jù)類都有說(shuō)道,在ActivityManagerService-B中對(duì)ActivityRecord 的狀態(tài)變化做了一個(gè)介紹,Activity的狀態(tài)只是管理的結(jié)果,具體的過程需要需要詳細(xì)分析;本文將從幾個(gè)簡(jiǎn)單的場(chǎng)景結(jié)合代碼來(lái)分析Activity的管理過程;

場(chǎng)景1:Activity在AMS中的存在形式是ActivityRecord,應(yīng)用程序的組件是Activity,ActivityRecord與Activity是如何關(guān)聯(lián)的呢?——>static class Token extends IApplicationToken.Stub

這里涉及到到應(yīng)用程序的主線程-ActivityThread(ActivityThread其實(shí)并不是一個(gè)線程類),這個(gè)類已經(jīng)有很多人講解,這里推薦一篇關(guān)于ActivityThread和ApplicationThread的解析,ActivityThread有一個(gè)內(nèi)部類 ApplicationThread;
class ApplicationThread extends ApplicationThreadNative
class ApplicationThreadNative extends Binder implements IApplicationThread
AMS 和ActivityStackSupervisor中的 app.thread 就是這里ActivityThread的內(nèi)部類ApplicationThread對(duì)象;

Activity在ActivityThread中的存在形式是ActivityClientRecord;ActivityRecord有一個(gè)IApplicationToken.Stub類型的變量appToken,在構(gòu)造ActivityRecord的時(shí)候被初始化;

------>frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java
  static class Token extends IApplicationToken.Stub {
        final WeakReference<ActivityRecord> weakActivity;
        Token(ActivityRecord activity) {
            weakActivity = new WeakReference<ActivityRecord>(activity);
        }
        ......
------>frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java
    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration,
            ActivityRecord _resultTo, String _resultWho, int _reqCode,
            boolean _componentSpecified, ActivityStackSupervisor supervisor,
            ActivityContainer container, Bundle options) {
          service = _service;
          appToken = new Token(this);
          ......
    }

構(gòu)造一個(gè)ActivityRecord時(shí),會(huì)將自己(this)傳給Token,變量ActivityRecord.appToken存的就是最終創(chuàng)建出來(lái)的Token。

上述ActivityRecord.appToken的功能是什么呢?ActivityRecord是在Activity的啟動(dòng)過程中被初始化,繼續(xù)跟進(jìn)Activity的啟動(dòng)過程;

------>frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
------>frameworks\base\core\java\android\app\ActivityThread.java
ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...)
  ——> IApplicationThread.scheduleLaunchActivity(...,token, ...)
      ——>跨進(jìn)程調(diào)用,調(diào)用ActivityThread.ApplicationThread.scheduleLaunchActivity(...,token,...)
      ——>ApplicationThread.scheduleLaunchActivity(...token, ...)
        ——>ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY)
          ——>ActivityThread.performLaunchActivity(ActivityClientRecord, ...)
               ——>從ActivityActivityClientRecord取出token使用
               ——> Activity.attch(...token, ...) //attach中將token 賦值給Activity的mToken變量

通過上述函數(shù)調(diào)用,ActivityRecord的appToken就和應(yīng)用進(jìn)程的mToken建立關(guān)聯(lián);在發(fā)生Activity切換時(shí),應(yīng)用進(jìn)程會(huì)將上一個(gè)Activity的Token(AMS.startActivity()的輸入?yún)?shù)IBinder resultTo)傳遞給系統(tǒng)進(jìn)程,系統(tǒng)進(jìn)程會(huì)根據(jù)這個(gè)Token找到ActivityRecord,對(duì)其完成調(diào)度后,再通知應(yīng)用進(jìn)程:Activity狀態(tài)發(fā)生了變化。

場(chǎng)景2:?jiǎn)?dòng)新Activity時(shí),需要將新ActivityRecord壓入任務(wù)棧頂;

這里先用自然語(yǔ)言描述一下可能的情況:1:新的ActivityRecord 的任務(wù)棧已經(jīng)存在,處于后臺(tái),此時(shí)需要將這個(gè)后臺(tái)任務(wù)棧切換為前臺(tái)任務(wù)棧,然后將這個(gè)ActivityRecord置于前臺(tái)任務(wù)棧棧頂; 2:新ActivityRecord所在的任務(wù)棧沒有,需要新建任務(wù)棧,然后將ActivityRecord置于棧頂;

代碼邏輯:任務(wù)棧存在于后臺(tái)的情況:

第一步:需要先找到ActivityRecord所在的任務(wù)(TaskRecord);
第二步:將TaskRecord所在的ActivityStack移動(dòng)到前臺(tái);
第三步:將TaskRecord移動(dòng)到ActivityStack的棧頂;

1:找到ActivityRecord所在的TaskRecord: findTaskLocked()
------>frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
/**
 * 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);
    }
    ...
    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
        final TaskRecord task = mTaskHistory.get(taskNdx);
        ...
        final ActivityRecord r = task.getTopActivity();
            if (r == null || r.finishing || r.userId != userId ||
                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {//這些條件的直接過濾
                continue;
            }
        ...
        final Intent taskIntent = task.intent;
        final Intent affinityIntent = task.affinityIntent;
        ...
        if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
            if (task.rootAffinity.equals(target.taskAffinity)) { //Affinity和Task的rootAffinity相同,
            //則就是這個(gè)task 了;
                return r;
            }
        } else if (taskIntent != null && taskIntent.getComponent() != null &&
            taskIntent.getComponent().compareTo(cls) == 0 &&
            Objects.equals(documentData, taskDocumentData)) {//Task的Intent 和target的包名相同
            return r;
        } else if if (affinityIntent != null && affinityIntent.getComponent() != null &&
            affinityIntent.getComponent().compareTo(cls) == 0 &&
            Objects.equals(documentData, taskDocumentData)) { //Affinity Intent的包名相同
            return r
        }
        ...
    }
    return null;
}

改函數(shù)主要是對(duì)ActivityStack中的所有Task進(jìn)行遍歷,找到ActivityRecord的所在的Task,如果找到Task,則返回Task最上面的ActivityRecord;找到Task的條件如下:

  • ActivityRecord target 的affinity和正在遍歷的Task的rootAffinity相同;
  • ActivityRecord target的包名和Task的intent 的包名相同;
  • ActivityRecord target的包名和Task的affinityIntent的包名相同;
2:將TaskRecord所在的ActivityStack調(diào)整到前臺(tái)
  • 2.1:findTaskLocked()方法找到Activity所在的Task的頂部ActivityRecord,根據(jù)這個(gè)ActivityRecord找到所在的TaskRecord和ActivityStack;
------> frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
                ......
                ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);
                if (intentActivity != null) {
                    ......
                    if (r.task == null) {
                        r.task = intentActivity.task;
                    }
                    targetStack = intentActivity.task.stack;//找到ActivityRecord r所在的ActivityStack
                    targetStack.mLastPausedActivity = null;
                    targetStack.moveToFront("intentActivityFound");
                  ......
  • 2.2:調(diào)整ActivityStack,主要根據(jù)ActivityStack的類型來(lái)進(jìn)行ActivityStack棧(mStacks)調(diào)整;moveToFront();
------>frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
final void moveToFront(String reason) {
        if (isAttached()) {//是否綁定到顯示設(shè)備
            if (isOnHomeDisplay()) {//是否顯示在默認(rèn)顯示設(shè)備
                mStackSupervisor.moveHomeStack(isHomeStack(), reason);//ActivityStack棧調(diào)整
            }
            mStacks.remove(this);//刪除mStacks棧中的該ActivityStack
            mStacks.add(this);//將該ActivityStack添加到mStacks中
            final TaskRecord task = topTask();
            if (task != null) {
                mWindowManager.moveTaskToTop(task.taskId);
            }
        }
    }

final boolean isHomeStack() {//判斷當(dāng)前ActivityStack 是不是HomeStack
        return mStackId == HOME_STACK_ID;
    }

void moveHomeStack(boolean toFront, String reason) {//棧調(diào)整
    // 獲取當(dāng)前的Top Stack
    ArrayList<ActivityStack> stacks = mHomeStack.mStacks;//mStacks代表的是綁定到顯示設(shè)備的所有Stack;
                          //所以這里也可以用mFocusedStack.mStacks
    final int topNdx = stacks.size() - 1;
    if (topNdx <= 0) {
        return;
    }
    ActivityStack topStack = stacks.get(topNdx);
    // HomeStack是否需要調(diào)整
    final boolean homeInFront = topStack == mHomeStack;//判斷stacks 棧頂?shù)腁ctivityStack是不是HomeStack,
    // 即判斷當(dāng)前HomeStack是不是在前臺(tái);
    if (homeInFront != toFront) {
        mLastFocusedStack = topStack;
        stacks.remove(mHomeStack);
        stacks.add(toFront ? topNdx : 0, mHomeStack);//這里根據(jù)toFront來(lái)調(diào)整HomeStack位置
        mFocusedStack = stacks.get(topNdx);//調(diào)整mFocusedStack
    }
    ...
    if (mService.mBooting || !mService.mBooted) {  // 開機(jī)過程處理
        final ActivityRecord r = topRunningActivityLocked();
        if (r != null && r.idle) {
            checkFinishBootingLocked();
        }
    }
}

moveHomeStack()方法根據(jù)mStacks棧頂?shù)腁ctivityStack是否是HomeStack來(lái)對(duì)HomeStack和mFocusedStack 進(jìn)行調(diào)整;homeInFront 表示mStacks棧頂是不是HomeStack(即HomeStack 是否在前臺(tái));toFront 是isHomeStack()的返回值,即當(dāng)前ActivityStack是否是HomeStack,也就是需要將當(dāng)前ActivityStack調(diào)整到前臺(tái)還是后臺(tái);

這里存在如下4種情況:

  • homeInFront = true,即topStack == mHomeStack, 表示當(dāng)前mStacks最頂?shù)臈J荋omeStack,即表示HomeStack在前臺(tái);toFront = false 即isHomeStack()返回false,即表示ActivityRecord所在的棧不是HomeStack,所以需要將HomeStack調(diào)整到mStacks的底部,即將HomeStack調(diào)整到mStacks的0號(hào)位置;
  • homeInFront = true, toFront = true: 表示HomeStack在前臺(tái),要顯示的ActivityStack就是HomeStack,所以不需要對(duì)mStacks進(jìn)行調(diào)整;
  • homeInFront = false, toFront = true: 表示HomeStack在后臺(tái),要顯示的ActivityStack就是HomeStack,需要將HomeStack調(diào)整到mStacks的最頂端;
  • homeInFront = false, toFront = false: 表示HomeStack在后臺(tái),要顯示的ActivityStack 也 是HomeStack,不需要對(duì)mStacks進(jìn)行調(diào)整。

moveToFront中moveHomeStack()調(diào)整完HomeStack位置后,調(diào)整mStacks棧中當(dāng)前ActivityStack位置,即先刪除當(dāng)前ActivityStack,然后再向mStacks中添加當(dāng)前ActivityStack(這樣做時(shí)為了保證將當(dāng)前ActivityStack置于棧頂);

3:將當(dāng)前需要顯示的ActivityRecord的TaskRecord 移動(dòng)到ActivityStack 的棧頂;moveTaskToFrontLocked()

ActivityStack有前臺(tái)和后臺(tái)之分,前臺(tái)ActivityStack代表當(dāng)前顯示的ActivityRecord在的TaskRecord所在的ActivityStack(不是前臺(tái)ActivityStack中所有的TaskRecord 和ActivityRecord都處于可見,只有ActivityStack 棧頂?shù)腡askRecord 棧頂?shù)腁ctivityRecord處于可見狀態(tài));

第二步已經(jīng)將ActivityRecord所在的Task的Stack移動(dòng)到前臺(tái),現(xiàn)在需要將需要顯示的ActivityRecord 所在的TaskRecord 移動(dòng)到ActivityStack的棧頂,以及將ActivityRecord移動(dòng)到TaskRecord的棧頂;

------> frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord source, Bundle options,
            String reason) {
        final int numTasks = mTaskHistory.size();
        final int index = mTaskHistory.indexOf(tr);
        if (numTasks == 0 || index < 0)  { //numTasks 代表當(dāng)前ActivityStack中的所有TaskRecord數(shù)量,
        //index 表示當(dāng)前需要調(diào)整的TaskRecord在ActivityStack mTaskHistory中的位置
            // nothing to do!
            if (source != null &&
                    (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                ActivityOptions.abort(options);
            } else {
                updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
            }
            return;
        }

        // Shift all activities with this task up to the top
        // of the stack, keeping them in the same internal order.
        insertTaskAtTop(tr);//將Task置于ActivityStack棧頂
        moveToFront(reason);//前面說(shuō)過moveToFront()方法,前面的情況只調(diào)用了moveToFront(),
        //不會(huì)調(diào)用moveTaskToFrontLocked(); 
        //一旦要將任務(wù)調(diào)整到ActivityStack棧頂,意味著ActivityStack也一定要調(diào)整到前臺(tái);

        if (source != null &&
                (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
            ActivityRecord r = topRunningActivityLocked(null);
            if (r != null) {
                mNoAnimActivities.add(r);
            }
            ActivityOptions.abort(options);
        } else {
            updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
        }

        mStackSupervisor.resumeTopActivitiesLocked();//當(dāng)Activity各種棧調(diào)整好后,就可以將當(dāng)前Activity的狀態(tài)置為RESUMED
        ......
    }

private void insertTaskAtTop(TaskRecord task) {
        // If this is being moved to the top by another activity or being launched from the home
        // activity, set mOnTopOfHome accordingly.
        if (isOnHomeDisplay()) {
            ActivityStack lastStack = mStackSupervisor.getLastStack();
            final boolean fromHome = lastStack.isHomeStack();
            if (!isHomeStack() && (fromHome || topTask() != task)) {
                task.setTaskToReturnTo(fromHome
                        ? lastStack.topTask() == null
                                ? HOME_ACTIVITY_TYPE
                                : lastStack.topTask().taskType
                        : APPLICATION_ACTIVITY_TYPE);//設(shè)置ReturnTo Task類型
            }
        } else {
            task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
        }
        mTaskHistory.remove(task);//先從mTaskHistory中移除task
        // Now put task at top.
        int taskNdx = mTaskHistory.size();
        if (!isCurrentProfileLocked(task.userId)) {
            // Put non-current user tasks below current user tasks.
            while (--taskNdx >= 0) {
                if (!isCurrentProfileLocked(mTaskHistory.get(taskNdx).userId)) {
                    break;
                }
            }
            ++taskNdx;
        }
        mTaskHistory.add(taskNdx, task);//將task添加到mTaskHistory,確保添加到了頂部
        updateTaskMovement(task, true);
    }

這里將ActivityRecord所在的TaskRecord 移動(dòng)到ActivityStack的棧頂,還需要將需要顯示的ActivityRecord移動(dòng)到TaskRecord的棧頂,這個(gè)過程通過addActivityToTop()來(lái)實(shí)現(xiàn);addActivityToTop()在ActivityStack.java的startActivityLocked()方法中被調(diào)用,startActivityLocked()在ActivityStackSupervisor.java的startActivityUncheckedLocked()方法中被調(diào)用;

------> frameworks\base\services\core\java\com\android\server\am\TaskRecord.java
    void addActivityToTop(ActivityRecord r) {
        addActivityAtIndex(mActivities.size(), r);
    }

    void addActivityAtIndex(int index, ActivityRecord r) {
        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
        if (!mActivities.remove(r) && r.fullscreen) {//刪除mActivities中已經(jīng)存在的r
            // Was not previously in list.
            numFullscreen++;
        }
        // Only set this based on the first activity
        if (mActivities.isEmpty()) { //判斷當(dāng)前啟動(dòng)的Activity是否為該任務(wù)Task的第一個(gè)Activity
            taskType = r.mActivityType;
            isPersistable = r.isPersistable();
            mCallingUid = r.launchedFromUid;
            mCallingPackage = r.launchedFromPackage;
            // Clamp to [1, max].
            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
                    ActivityManager.getMaxAppRecentsLimitStatic());
        } else {
            // Otherwise make all added activities match this one.
            r.mActivityType = taskType;
        }
        Log.d(TAG+"mActivities.add",Log.getStackTraceString(new Throwable()));//Keiven-chen
        mActivities.add(index, r);//指定將當(dāng)前Activity添加到mActivities中的位置
        updateEffectiveIntent();//如函數(shù)名,更新任務(wù)棧相關(guān)Intent
        if (r.isPersistable()) {
            mService.notifyTaskPersisterLocked(this, false);
        }
    }

這里需要明確一點(diǎn)問題,mActivities就是我說(shuō)的TaskRecord棧, mTaskHistory也就是ActivityStack棧;

場(chǎng)景3: 任務(wù)棧會(huì)經(jīng)常調(diào)整,任務(wù)棧剛開始從底到頂是 A - B - C, 經(jīng)過調(diào)整后任務(wù)棧變化為 C - B - A,這個(gè)過程會(huì)對(duì)整個(gè)任務(wù)棧帶來(lái)哪些改變呢?

該問題看似只需要調(diào)整mActivities的順序,但是會(huì)這么簡(jiǎn)單嗎?ActivityManagerService-A文中有說(shuō)過TaskRecord類,隨著mActivities棧的改變,TaskRecord中的屬性是否也應(yīng)該改變呢?比如Affinity,Intent;這些值是如何改變的呢?這里涉及updateEffectiveIntent()和setFrontOfTask();

每次調(diào)整完mActivities后,需要調(diào)用updateEffectiveIntent方法來(lái)修改該TaskRecord相關(guān)的Intent;

void updateEffectiveIntent() {
    final int effectiveRootIndex = findEffectiveRootIndex();//找到根Activity索引
    final ActivityRecord r = mActivities.get(effectiveRootIndex);
    setIntent(r);//設(shè)置Intent相關(guān)屬性,順著代碼往下看,
}
    /** Sets the original intent, and the calling uid and package. */
    void setIntent(ActivityRecord r) {
        setIntent(r.intent, r.info);
        mCallingUid = r.launchedFromUid;
        mCallingPackage = r.launchedFromPackage;
    }

    /** Sets the original intent, _without_ updating the calling uid or package. */
    private void setIntent(Intent _intent, ActivityInfo info) { //該重載方法更新affinity, 
    //origActivity ,realActivity等屬性;
        if (intent == null) {
            mNeverRelinquishIdentity =
                    (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
        } else if (mNeverRelinquishIdentity) {
            return;
        }

        affinity = info.taskAffinity;
        if (intent == null) {
            // If this task already has an intent associated with it, don't set the root
            // affinity -- we don't want it changing after initially set, but the initially
            // set value may be null.
            rootAffinity = affinity;
        }
        effectiveUid = info.applicationInfo.uid;
        stringName = null;

        if (info.targetActivity == null) {
            if (_intent != null) {
                // If this Intent has a selector, we want to clear it for the
                // recent task since it is not relevant if the user later wants
                // to re-launch the app.
                if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
                    _intent = new Intent(_intent);
                    _intent.setSelector(null);
                    _intent.setSourceBounds(null);
                }
            }
            if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
                    "Setting Intent of " + this + " to " + _intent);
            intent = _intent;
            realActivity = _intent != null ? _intent.getComponent() : null;
            origActivity = null;
        } else {
            ComponentName targetComponent = new ComponentName(
                    info.packageName, info.targetActivity);
            if (_intent != null) {
                Intent targetIntent = new Intent(_intent);
                targetIntent.setComponent(targetComponent);
                targetIntent.setSelector(null);
                targetIntent.setSourceBounds(null);
                if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
                        "Setting Intent of " + this + " to target " + targetIntent);
                intent = targetIntent;
                realActivity = targetComponent;
                origActivity = _intent.getComponent();
            } else {
                intent = null;
                realActivity = targetComponent;
                origActivity = new ComponentName(info.packageName, info.name);
            }
        }

        final int intentFlags = intent == null ? 0 : intent.getFlags();
        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
            // Once we are set to an Intent with this flag, we count this
            // task as having a true root activity.
            rootWasReset = true;
        }

        userId = UserHandle.getUserId(info.applicationInfo.uid);
        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
            // If the activity itself has requested auto-remove, then just always do it.
            autoRemoveRecents = true;
        } else if ((intentFlags & (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
            // If the caller has not asked for the document to be retained, then we may
            // want to turn on auto-remove, depending on whether the target has set its
            // own document launch mode.
            if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
                autoRemoveRecents = false;
            } else {
                autoRemoveRecents = true;
            }
        } else {
            autoRemoveRecents = false;
        }
    }

任務(wù)棧A - B - C的棧底是 A,調(diào)整后, C - B - A的棧底是C,然而,TaskRecord并沒有標(biāo)注當(dāng)前棧底的屬性, 這個(gè)棧底是根據(jù)任務(wù)棧中每個(gè)ActivityRecord的frontOfTask屬性來(lái)標(biāo)識(shí):這個(gè)屬性通過setFrontOfTask()方法來(lái)修改;

/** Call after activity movement or finish to make sure that frontOfTask is set correctly */
    final void setFrontOfTask() {
        boolean foundFront = false;
        final int numActivities = mActivities.size();
        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {//重棧底開始
            final ActivityRecord r = mActivities.get(activityNdx);
            if (foundFront || r.finishing) {
                r.frontOfTask = false; //非棧底Activity 該屬性都置為false
            } else {
                r.frontOfTask = true;//棧底Activity 該屬性置為true
                // Set frontOfTask false for every following activity.
                foundFront = true;
            }
        }
        if (!foundFront && numActivities > 0) {
            // All activities of this task are finishing. As we ought to have a frontOfTask
            // activity, make the bottom activity front.
            mActivities.get(0).frontOfTask = true; //這種情況將mActivities第一個(gè)Activity的frontOfTask置為true;
        }
    }

該函數(shù)對(duì)任務(wù)棧從底到頂進(jìn)行遍歷,找到第一個(gè)未結(jié)束(finishing = false)的ActivityRecord, 將其frontOfTask屬性設(shè)置成true;其他所有ActivtyRecord的frontOfTask屬性設(shè)置為false。這樣就能標(biāo)記該ActivityRecord為所在任務(wù)棧的棧底;

參考文章:Android四大組件之Activity--管理方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容