ActivityRecord、TaskRecord、ActivityStack以及Activity啟動(dòng)模式詳解

1.簡(jiǎn)介

先來(lái)張簡(jiǎn)單的關(guān)系圖:


ActivityStack、TaskRecord、ActivityRecord關(guān)系圖.png
  • 一個(gè)ActivityRecord對(duì)應(yīng)一個(gè)Activity,保存了一個(gè)Activity的所有信息;但是一個(gè)Activity可能會(huì)有多個(gè)ActivityRecord,因?yàn)?code>Activity可以被多次啟動(dòng),這個(gè)主要取決于其啟動(dòng)模式。
  • 一個(gè)TaskRecord由一個(gè)或者多個(gè)ActivityRecord組成,這就是我們常說(shuō)的任務(wù)棧,具有后進(jìn)先出的特點(diǎn)。
  • ActivityStack則是用來(lái)管理TaskRecord的,包含了多個(gè)TaskRecord。

下面進(jìn)入詳細(xì)的代碼分析,本文源碼基于android 27。

2.代碼分析

2.1 ActivityRecord

ActivityRecord,源碼中的注釋介紹:An entry in the history stack, representing an activity.
翻譯:歷史棧中的一個(gè)條目,代表一個(gè)activity。

    frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
    
    final class ActivityRecord extends ConfigurationContainer implements AppWindowContainerListener {

        final ActivityManagerService service; // owner
        final IApplicationToken.Stub appToken; // window manager token
        AppWindowContainerController mWindowContainerController;
        final ActivityInfo info; // all about me
        final ApplicationInfo appInfo; // information about activity's app
        
        //省略其他成員變量
        
        //ActivityRecord所在的TaskRecord
        private TaskRecord task;        // the task this is in.
        
        //構(gòu)造方法,需要傳遞大量信息
        ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,
                       int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
                       ActivityInfo aInfo, Configuration _configuration,
                       com.android.server.am.ActivityRecord _resultTo, String _resultWho, int _reqCode,
                       boolean _componentSpecified, boolean _rootVoiceInteraction,
                       ActivityStackSupervisor supervisor, ActivityOptions options,
                       com.android.server.am.ActivityRecord sourceRecord) {
        
        }
    }
  • 實(shí)際上,ActivityRecord中存在著大量的成員變量,包含了一個(gè)Activity的所有信息。
  • ActivityRecord中的成員變量task表示其所在的TaskRecord,由此可以看出:ActivityRecordTaskRecord建立了聯(lián)系。

startActivity()時(shí)會(huì)創(chuàng)建一個(gè)ActivityRecord

    frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

    class ActivityStarter {
        private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
                                  String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
                                  IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                  IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
                                  String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
                                  ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
                                  com.android.server.am.ActivityRecord[] outActivity, TaskRecord inTask) {

            //其他代碼略
            
            ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                    callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                    resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                    mSupervisor, options, sourceRecord);
                    
            //其他代碼略
        }
    }

2.2 TaskRecord

TaskRecord,內(nèi)部維護(hù)一個(gè)ArrayList<ActivityRecord>用來(lái)保存ActivityRecord

    frameworks/base/services/core/java/com/android/server/am/TaskRecord.java
    
    final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
        final int taskId;       //任務(wù)ID
        final ArrayList<ActivityRecord> mActivities;   //使用一個(gè)ArrayList來(lái)保存所有的ActivityRecord
        private ActivityStack mStack;   //TaskRecord所在的ActivityStack
        
        //構(gòu)造方法
        TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
                   IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
            
        }
        
        //添加Activity到頂部
        void addActivityToTop(com.android.server.am.ActivityRecord r) {
            addActivityAtIndex(mActivities.size(), r);
        }
        
        //添加Activity到指定的索引位置
        void addActivityAtIndex(int index, ActivityRecord r) {
            //...

            r.setTask(this);//為ActivityRecord設(shè)置TaskRecord,就是這里建立的聯(lián)系

            //...
            
            index = Math.min(size, index);
            mActivities.add(index, r);//添加到mActivities
            
            //...
        }

        //其他代碼略
    }
  • 可以看到TaskRecord中使用了一個(gè)ArrayList來(lái)保存所有的ActivityRecord。
  • 同樣,TaskRecord中的mStack表示其所在的ActivityStack

startActivity()時(shí)也會(huì)創(chuàng)建一個(gè)TaskRecord

    frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
    
    class ActivityStarter {

        private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
            mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);

            if (mReuseTask == null) {
                //創(chuàng)建一個(gè)createTaskRecord,實(shí)際上是調(diào)用ActivityStack里面的createTaskRecord()方法,ActivityStack下面會(huì)講到
                final TaskRecord task = mTargetStack.createTaskRecord(
                        mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                        mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                        mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                        mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);

                //其他代碼略
            }
        }
    }

2.3 ActivityStack

ActivityStack,內(nèi)部維護(hù)了一個(gè)ArrayList<TaskRecord>,用來(lái)管理TaskRecord。

    frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
    
    class ActivityStack<T extends StackWindowController> extends ConfigurationContainer implements StackWindowListener {

        private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();//使用一個(gè)ArrayList來(lái)保存TaskRecord

        final int mStackId;

        protected final ActivityStackSupervisor mStackSupervisor;//持有一個(gè)ActivityStackSupervisor,所有的運(yùn)行中的ActivityStacks都通過(guò)它來(lái)進(jìn)行管理
        
        //構(gòu)造方法
        ActivityStack(ActivityStackSupervisor.ActivityDisplay display, int stackId,
                      ActivityStackSupervisor supervisor, RecentTasks recentTasks, boolean onTop) {

        }
        
        TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
                                    IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                    boolean toTop, int type) {
                                    
            //創(chuàng)建一個(gè)task
            TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession, voiceInteractor, type);
            
            //將task添加到ActivityStack中去
            addTask(task, toTop, "createTaskRecord");

            //其他代碼略

            return task;
        }
        
        //添加Task
        void addTask(final TaskRecord task, final boolean toTop, String reason) {

            addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason);

            //其他代碼略
        }

        //添加Task到指定位置
        void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange,
                     String reason) {
            mTaskHistory.remove(task);//若存在,先移除
            
            //...
            
            mTaskHistory.add(position, task);//添加task到mTaskHistory
            task.setStack(this);//為TaskRecord設(shè)置ActivityStack

            //...
        }
        
        //其他代碼略
    }
  • 可以看到ActivityStack使用了一個(gè)ArrayList來(lái)保存TaskRecord。
  • 另外,ActivityStack中還持有ActivityStackSupervisor對(duì)象,這個(gè)是用來(lái)管理ActivityStacks的。

ActivityStack是由ActivityStackSupervisor來(lái)創(chuàng)建的,實(shí)際ActivityStackSupervisor就是用來(lái)管理ActivityStack的,繼續(xù)看下面的ActivityStackSupervisor分析。

2.4 ActivityStackSupervisor

ActivityStackSupervisor,顧名思義,就是用來(lái)管理ActivityStack的。

    frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    
    public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {

        ActivityStack mHomeStack;//管理的是Launcher相關(guān)的任務(wù)

        ActivityStack mFocusedStack;//管理非Launcher相關(guān)的任務(wù)
        
        //創(chuàng)建ActivityStack
        ActivityStack createStack(int stackId, ActivityStackSupervisor.ActivityDisplay display, boolean onTop) {
            switch (stackId) {
                case PINNED_STACK_ID:
                    //PinnedActivityStack是ActivityStack的子類
                    return new PinnedActivityStack(display, stackId, this, mRecentTasks, onTop);
                default:
                    //創(chuàng)建一個(gè)ActivityStack
                    return new ActivityStack(display, stackId, this, mRecentTasks, onTop);
            }
        }

    }
  • ActivityStackSupervisor內(nèi)部有兩個(gè)不同的ActivityStack對(duì)象:mHomeStack、mFocusedStack,用來(lái)管理不同的任務(wù)。
  • ActivityStackSupervisor內(nèi)部包含了創(chuàng)建ActivityStack對(duì)象的方法。

AMS初始化時(shí)會(huì)創(chuàng)建一個(gè)ActivityStackSupervisor對(duì)象。

2.5 總結(jié)

所以,實(shí)際上,他們的關(guān)系應(yīng)該是這樣的:


ActivityStack、TaskRecord、ActivityRecord、ActivityStackSupervisor關(guān)系圖.png

3. 場(chǎng)景分析

下面通過(guò)啟動(dòng)Activity的代碼來(lái)分析一下:

3.1 桌面

首先,我們看下處于桌面時(shí)的狀態(tài),運(yùn)行命令:

adb shell dumpsys activity

結(jié)果如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #0:
  
  //中間省略其他...
  
    Task id #102
    
  //中間省略其他...
  
      TaskRecord{446ae9e #102 I=com.google.android.apps.nexuslauncher/.NexusLauncherActivity U=0 StackId=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.google.android.apps.nexuslauncher/.NexusLauncherActivity }
        Hist #0: ActivityRecord{54fa22 u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t102}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.google.android.apps.nexuslauncher/.NexusLauncherActivity }
          ProcessRecord{19c7c43 2203:com.google.android.apps.nexuslauncher/u0a22}

    Running activities (most recent first):
      TaskRecord{446ae9e #102 I=com.google.android.apps.nexuslauncher/.NexusLauncherActivity U=0 StackId=0 sz=1}
        Run #0: ActivityRecord{54fa22 u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t102}

    mResumedActivity: ActivityRecord{54fa22 u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t102}
    
//省略其他

實(shí)際上就是如下圖所示的結(jié)構(gòu),這里的Stack #0就是ActivityStackSupervisor中的mHomeStack,mHomeStack管理的是Launcher相關(guān)的任務(wù)。

桌面下的狀態(tài).png

3.2 從桌面啟動(dòng)一個(gè)Activity

從桌面啟動(dòng)一個(gè)APP,然后運(yùn)行上面的命令,為了節(jié)省篇幅,這里和后面就不貼結(jié)果了,直接放圖了。

從桌面點(diǎn)擊圖標(biāo)啟動(dòng)一個(gè)AActivity,可以看到,會(huì)多了一個(gè)Stack #1,這個(gè)Stack #1就是ActivityStackSupervisor中的mFocusedStack,mFocusedStack負(fù)責(zé)管理的是非Launcher相關(guān)的任務(wù)。同時(shí)也會(huì)創(chuàng)建一個(gè)新的ActivityRecordTaskRecord,ActivityRecord放到TaskRecord中,TaskRecord則放進(jìn)mFocusedStack中。

啟動(dòng)A.png

3.3 默認(rèn)模式從A啟動(dòng)B

然后,我們從AActivity中啟動(dòng)一個(gè)BActivity,可以看到會(huì)創(chuàng)建一個(gè)新的ActivityRecord然后放到已有的TaskRecord棧頂。

默認(rèn)(standerd)模式啟動(dòng)B.png

3.4 從A啟動(dòng)B創(chuàng)建新棧

如果我們想啟動(dòng)的BActivity在一個(gè)新的棧中呢,我們可以用singleInstance的方式來(lái)啟動(dòng)BActivity。singleInstance后面也會(huì)講到。這種方式會(huì)創(chuàng)建一個(gè)新的ActivityRecordTaskRecord,把ActivityRecord放到新的TaskRecord中去。

啟動(dòng)新Task.png

4. 流程分析

4.1 啟動(dòng)流程

這里對(duì)啟動(dòng)Activity過(guò)程中涉及到的ActivityStack、TaskRecord、ActivityRecordActivityStackSupervisor進(jìn)行簡(jiǎn)單的分析,實(shí)際上一張時(shí)序圖就可以看明白了。相關(guān)的代碼可以看上面的內(nèi)容。

Activity啟動(dòng)UML類圖.png

簡(jiǎn)單總結(jié):
1.startActivity時(shí)首先會(huì)創(chuàng)建一個(gè)ActivityRecord
2.如果有需要,會(huì)創(chuàng)建一個(gè)TaskRecord,并把這個(gè)TaskRecord加入到ActivityStack中。
3.將ActivityRecord添加到TaskRecord的棧頂。

5. 啟動(dòng)模式

相信看完上面的介紹,現(xiàn)在再來(lái)看啟動(dòng)模式那是so easy了。

5.1 standerd

默認(rèn)模式,每次啟動(dòng)Activity都會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例。

比如:現(xiàn)在有個(gè)A Activity,我們?cè)贏上面啟動(dòng)B,再然后在B上面啟動(dòng)A,其過(guò)程如圖所示:

standerd.png

5.2 singleTop

如果要啟動(dòng)的Activity已經(jīng)在棧頂,則不會(huì)重新創(chuàng)建Activity,只會(huì)調(diào)用該該Activity的onNewIntent()方法。
如果要啟動(dòng)的Activity不在棧頂,則會(huì)重新創(chuàng)建該Activity的實(shí)例。

比如:現(xiàn)在有個(gè)A Activity,我們?cè)贏以standerd模式上面啟動(dòng)B,然后在B上面以singleTop模式啟動(dòng)A,其過(guò)程如圖所示,這里會(huì)新創(chuàng)建一個(gè)A實(shí)例:

singleTop_A.png

如果在B上面以singleTop模式啟動(dòng)B的話,則不會(huì)重新創(chuàng)建B,只會(huì)調(diào)用onNewIntent()方法,其過(guò)程如圖所示:

singleTop_B.png

5.3 singleTask

如果要啟動(dòng)的Activity已經(jīng)存在于它想要?dú)w屬的棧中,那么不會(huì)創(chuàng)建該Activity實(shí)例,將棧中位于該Activity上的所有的Activity出棧,同時(shí)該Activity的onNewIntent()方法會(huì)被調(diào)用。
如果要啟動(dòng)的Activity不存在于它想要?dú)w屬的棧中,并且該棧存在,則會(huì)創(chuàng)建該Activity的實(shí)例。
如果要啟動(dòng)的Activity想要?dú)w屬的棧不存在,則首先要?jiǎng)?chuàng)建一個(gè)新棧,然后創(chuàng)建該Activity實(shí)例并壓入到新棧中。

比如:現(xiàn)在有個(gè)A Activity,我們?cè)贏以standerd模式上面啟動(dòng)B,然后在B上面以singleTask模式啟動(dòng)A,其過(guò)程如圖所示:

singleTask.png

5.4 singleInstance

基本和singleTask一樣,不同的是啟動(dòng)Activity時(shí),首先要?jiǎng)?chuàng)建在一個(gè)新棧,然后創(chuàng)建該Activity實(shí)例并壓入新棧中,新棧中只會(huì)存在這一個(gè)Activity實(shí)例。

比如:現(xiàn)在有個(gè)A Activity,我們?cè)贏以singleInstance模式上面啟動(dòng)B,其過(guò)程如圖所示:

singleInstance.png

6.Intent的FLAG

另外,如果startActivity()時(shí)往Intent 中加入相應(yīng)的標(biāo)志來(lái)指定啟動(dòng)模式,這種方式的優(yōu)先級(jí)會(huì)比在AndroidManifest中定義的優(yōu)先級(jí)高;但是AndroidManifest中只能定義四種啟動(dòng)方式:standardsingleTop、singleTasksingleInstance,而Intentflag則有很多種。具體的可以看看文檔,我們這里看看部分flag

  • FLAG_ACTIVITY_NEW_TASK :跟launchMode中的singleTask一樣。
  • FLAG_ACTIVITY_SINGLE_TOP :跟launchMode中的singleTop一樣。
  • FLAG_ACTIVITY_CLEAR_TOPlaunchMode中沒(méi)有對(duì)應(yīng)的值,如果要啟動(dòng)的Activity已經(jīng)存在于棧中,則將所有位于它上面的Activity出棧。singleTask默認(rèn)具有此標(biāo)記位的效果。
?著作權(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)容