天天看點

Android——帶你從ADB指令行檢視Task任務棧的管理方式一、概念二、任務棧的切換示範:情況一:單一Task&預設的啟動模式下,App切換時的Activity棧情況情況二:單一Task&含有SingleTask的模式,App切換的Activity棧情況情況三:多Task&SingleTask模式,App切換時Activity棧的情況三、總結

  • 一概念
    • 1Task
    • 2ActivityStack
    • 3ActivityRecordProcessRecord
  • 二任務棧的切換示範
  • 情況一單一Task預設的啟動模式下App切換時的Activity棧情況
    • 1從App2ActivityB啟動App1ActivityA
    • 2接着上面我們又從App1ActivityA啟動App2ActivityB
  • 情況二單一Task含有SingleTask的模式App切換的Activity棧情況
    • 1從ActivityB切換至ActivityA
    • 2将MainActivity啟動模式變為singleTask這時如果我們從App2ActivityB切換至App1MainActivity會發什麼
  • 情況三多TaskSingleTask模式App切換時Activity棧的情況
    • 1從App2ActivatyB啟動App1ActivityA
    • 2從App2ActivityB啟動App1MainActivity
  • 三總結

一、概念

1、Task

Task是指将相關的Activity組合到一起,以Activity Stack的方式進行管理。從使用者體驗上講,一個“應用程式”就是一個Task(預設情況),但是從根本上講,一個Task是可以有一個或多個Android Application組成的。

Task表示一個任務,每一個Task 會有一個ID作為唯一辨別。一個程序(程式)有一個預設的task affinity,預設為包名,也可以多個程式指定同一個TaskAffinity。Activity的啟動會進入到對應的Task當中或者重新啟動一個新的Task。Android源碼裡面有一個TaskRecord類,該類的一個執行個體就對應着一個Task。

一組Task以連結清單的方式互相連接配接,每一個Task會有一個前驅任務點和後繼任務點,以此來管理Task的編輯和查找。ActivityStack外部以連結清單的形式管理Task,Task内部以後進先出的曆史順序方式管理Activity。

下面的Task的一段源碼,我們可以看到它的主要結構:

final class TaskRecord {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
    ......
    static final String ATTR_TASKID = "task_id";
    ......
    //任務的前驅節點
    TaskRecord mPrevAffiliate; // previous task in affiliated chain.
    int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
    //該任務的後繼節點
    TaskRecord mNextAffiliate; // next task in affiliated chain.
    int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
    ......

    /** List of all activities in the task arranged in history order */
    //該Task下的Activity,以後進先出的方式存放
    final ArrayList<ActivityRecord> mActivities;

    /** 目前的Activity棧 */
    ActivityStack stack;
}
           

2、ActivityStack

Stack表示任務棧,任務棧是以Task為基本機關的。一般我們的程式切換就是Task的切換,一個程式從背景任務棧到前台任務棧,是整個任務棧的移動,而不僅僅是Activity的移動,在任務棧移動之後,再按照LaunchModel的規則對Activity進行操作。與Stack相對應的有Android源碼裡面的ActivityStack類。一般來說,我們的應用程式都在一個單例的ActivityStack當中。

ActivityStack裡面還維護着一個Activity的LRU運作清單,按照最近通路且正在運作的Activity排列。

/**
 * 單列的Activity棧
 * State and management of a single stack of activities.
 */
final class ActivityStack {
    /**
     * List of running activities, sorted by recent usage.
     * The first entry in the list is the least recently used.
     * It contains HistoryRecord objects.
    */
    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();

}
           

這個是使用adb shell dumpsys activity 檢視Activity棧資訊的時候列印出來的一個LRU的Activity清單。

//LRU的方式管理的正在運作的Activity清單
 Running activities (most recent first):
   //#276表示該Task的TaskID;  A = com.example.malingyi.testtask1 表示該Task的TaskAffinity值,sz = 2表示該Task内部Activity的數量
    TaskRecord{a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
     Run #3: ActivityRecord{c5e365e u0 com.example.malingyi.testtask1/.ActivityA t276}
   TaskRecord{c2a15 #277 A=com.example.malingyi.testtask2 U=0 sz=2}
     Run #2: ActivityRecord{e3bed35 u0 com.example.malingyi.testtask2/.ActivityB t277}
     Run #1: ActivityRecord{532f30e u0 com.example.malingyi.testtask2/.MainActivity t277}
   TaskRecord{a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
     Run #0: ActivityRecord{e5c7c57 u0 com.example.malingyi.testtask1/.MainActivity t276}


 //前台正在運作的Activity
 mResumedActivity: ActivityRecord{a73c94 u0 com.example.malingyi.testtask2/.ActivityA t253}
           

3、ActivityRecord、ProcessRecord

ActivityRecord:代表着一個在Task裡面正在活動的Acitivty的資訊記錄。

/**
 * An entry in the history stack, representing an activity.
 */
final class ActivityRecord {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
    ...

    final ActivityManagerService service; // owner
    final IApplicationToken.Stub appToken; // window manager token
    final ActivityInfo info; // all about me
    final ApplicationInfo appInfo; // information about activity's app
    final int userId;          // Which user is this running for?
    final Intent intent;    // the original intent that generated us
    final ComponentName realActivity;  // the intent component, or target of an alias.
    ...

    //包的名稱
    final String packageName; // the package implementing intent's component
    //程序的名稱
    final String processName; // process where this component wants to run
    //Task的名稱
    final String taskAffinity; // as per ActivityInfo.taskAffinity


    //Activity所在的任務棧
    TaskRecord task;        // the task this is in.
    ...
}
           

ProcessRecord:目前運作的程序資訊,描述了該程序的所有資訊。

/**
 * Full information about a particular process that
 * is currently running.
 */
final class ProcessRecord {
    ...
}
           

二、任務棧的切換示範:

假設:

有兩個程式:App1、App2,包名為:App1 = com.example.malingyi.testtask1 App2 = com.example.malingyi.testtask1;

ActivityA屬于App1、ActivityB屬于App2;兩個App都有MainActivity作為啟動入口。

情況一:單一Task&預設的啟動模式下,App切換時的Activity棧情況

啟動模式:

ActivityA:standard

ActivityB:standard

App1、App2:MainActivity:standard

TaskAffinity:

都是預設情況下的TaskAffinity(包名)

初始化啟動順序:

Step1:啟動App1:MainActivity——>ActivityA ;

Step2:啟動App2:MainActivity——>ActivityB;

**棧頂Activity:**ActivityB

Activity棧:

App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

初始任務棧資訊如下:

Stack #8:
    Task id #282 //App2的Task棧
      TaskRecord{cde1503 #282 A=com.example.malingyi.testtask2 U=0 sz=2}  //Task資訊
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
        Hist #1: ActivityRecord{218b549 u0 com.example.malingyi.testtask2/.ActivityB t282}//Activity資訊
          Intent { cmp=com.example.malingyi.testtask2/.ActivityB }
          ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}
        Hist #0: ActivityRecord{735919e u0 com.example.malingyi.testtask2/.MainActivity t282}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63} //程序資訊
    Task id #281。//App1的Task棧
      TaskRecord{c80 #281 A=com.example.malingyi.testtask1 U=0 sz=2}  //Task資訊
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
        Hist #1: ActivityRecord{66d10ee u0 com.example.malingyi.testtask1/.ActivityA t281}//Activity資訊
          Intent { cmp=com.example.malingyi.testtask1/.ActivityA }
          ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
        Hist #0: ActivityRecord{157ed43 u0 com.example.malingyi.testtask1/.MainActivity t281}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60} //程序資訊
           

(1)從App2.ActivityB啟動App1.ActivityA

切換後任務棧:

Stack #8:
   Task id #282  //棧頂還是App2的Task,APP.ActivityA進入了App2的Task棧中。
     TaskRecord{cde1503 #282 A=com.example.malingyi.testtask2 U=0 sz=3}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
       Hist #2: ActivityRecord{c6170ac u0 com.example.malingyi.testtask1/.ActivityA t282}
         Intent { act=com.exaple.malingyi.ActivityA cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
       Hist #1: ActivityRecord{218b549 u0 com.example.malingyi.testtask2/.ActivityB t282}
         Intent { cmp=com.example.malingyi.testtask2/.ActivityB }
         ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}
       Hist #0: ActivityRecord{735919e u0 com.example.malingyi.testtask2/.MainActivity t282}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}

   Task id #281
     TaskRecord{c80 #281 A=com.example.malingyi.testtask1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
       Hist #1: ActivityRecord{66d10ee u0 com.example.malingyi.testtask1/.ActivityA t281}
         Intent { cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
       Hist #0: ActivityRecord{157ed43 u0 com.example.malingyi.testtask1/.MainActivity t281}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
           

初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

操作後的棧:App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB——>App1.ActivityA

這裡我們看到,App1.ActivityA重新建立了一個執行個體進入了App2的Task棧。

(2)接着上面,我們又從App1.ActivityA啟動App2.ActivityB

任務棧資訊:

Task id #282   //棧頂仍然是App2的Task,APP2.ActivityB進入了App2的Task棧中。
     TaskRecord{cde1503 #282 A=com.example.malingyi.testtask2 U=0 sz=4}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
       Hist #3: ActivityRecord{6e68c29 u0 com.example.malingyi.testtask2/.ActivityB t282}
         Intent { act=com.exaple.malingyi.ActivityB cmp=com.example.malingyi.testtask2/.ActivityB }
         ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}
       Hist #2: ActivityRecord{c6170ac u0 com.example.malingyi.testtask1/.ActivityA t282}
         Intent { act=com.exaple.malingyi.ActivityA cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
       Hist #1: ActivityRecord{218b549 u0 com.example.malingyi.testtask2/.ActivityB t282}
         Intent { cmp=com.example.malingyi.testtask2/.ActivityB }
         ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}
       Hist #0: ActivityRecord{735919e u0 com.example.malingyi.testtask2/.MainActivity t282}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{bd789 :com.example.malingyi.testtask2/u0a63}

   Task id #281
     TaskRecord{c80 #281 A=com.example.malingyi.testtask1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
       Hist #1: ActivityRecord{66d10ee u0 com.example.malingyi.testtask1/.ActivityA t281}
         Intent { cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
       Hist #0: ActivityRecord{157ed43 u0 com.example.malingyi.testtask1/.MainActivity t281}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{c82b9 :com.example.malingyi.testtask1/u0a60}
           

初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

操作後的棧:App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB——>App1.ActivityA——>App2.ActivityB

同樣,我們看到新啟動的ActivityB,還是在原有的App2的Task棧中。

這裡的到了兩個結論:

  • standard模式下,Activity會重新建立一個新的執行個體,不論原有執行個體是否存在。
  • standard模式下,Activity會進入啟動它的Activity所在的Task棧中,這個結論對于在啟動其他App的Activity也成立。

情況二:單一Task&含有SingleTask的模式,App切換的Activity棧情況

啟動模式:

ActivityA:SingleTask

ActivityB:SingleTask

App1、App2:MainActivity:standard

TaskAffinity:

都是預設情況下的TaskAffinity(包名)

初始化啟動順序:

Step1:啟動App1:MainActivity——>ActivityA ;

Step2:啟動App2:MainActivity——>ActivityB;

棧頂Activity:ActivityB

Activity棧:

App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

初始任務棧:

//所有啟動的Activity,按照Task來分組,按照任務的通路順序從上到下的排列。

Display #0 (activities from top to bottom):
  Stack #7:
    Task id #277   //App2的Task,裡面維護了Activity的入棧順序
      TaskRecord{c2a15 #277 A=com.example.malingyi.testtask2 U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
        Hist #1: ActivityRecord{e3bed35 u0 com.example.malingyi.testtask2/.ActivityB t277}
          Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
          ProcessRecord{d3fb1b :com.example.malingyi.testtask2/u0a63}
        Hist #0: ActivityRecord{532f30e u0 com.example.malingyi.testtask2/.MainActivity t277}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{d3fb1b :com.example.malingyi.testtask2/u0a63} //标明Task所屬的程序

    Task id #276。 //App1的Task,裡面維護了Activity的入棧順序
      TaskRecord{a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity }
        Hist #1: ActivityRecord{c5e365e u0 com.example.malingyi.testtask1/.ActivityA t276}
          Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
          ProcessRecord{a654b8 :com.example.malingyi.testtask1/u0a60}
        Hist #0: ActivityRecord{e5c7c57 u0 com.example.malingyi.testtask1/.MainActivity t276}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity }
          ProcessRecord{a654b8 :com.example.malingyi.testtask1/u0a60}  //标明Task所屬的程序


    //正在運作的是App2的ActivityB
    mResumedActivity: ActivityRecord{bf1f68 u0 com.example.malingyi.testtask1/com.example.malingyi.testtask2.ActivityB t272}
           

(1)從ActivityB切換至ActivityA:

切換後任務棧:

Stack #7:
   Task id #276 //App1的整個棧上移了!不止是Activity移到了前面,同時在Task下的MainActivity也一起移動了。
     TaskRecord{a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity }
       Hist #1: ActivityRecord{c5e365e u0 com.example.malingyi.testtask1/.ActivityA t276}
         Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{a654b8 :com.example.malingyi.testtask1/u0a60}
       Hist #0: ActivityRecord{e5c7c57 u0 com.example.malingyi.testtask1/.MainActivity t276}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity }
         ProcessRecord{a654b8 :com.example.malingyi.testtask1/u0a60}
   Task id #277 //App2的棧下調了
     TaskRecord{c2a15 #277 A=com.example.malingyi.testtask2 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
       Hist #1: ActivityRecord{e3bed35 u0 com.example.malingyi.testtask2/.ActivityB t277}
         Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
         ProcessRecord{d3fb1b :com.example.malingyi.testtask2/u0a63}
       Hist #0: ActivityRecord{532f30e u0 com.example.malingyi.testtask2/.MainActivity t277}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{d3fb1b :com.example.malingyi.testtask2/u0a63}

         初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB
         操作後的棧:App2.ActivityB——>App1.ActivityA——>App1.MainActivity——>App1.ActivityA
           

原本隻是從ActivityA切換到ActivityB,由于ActivityB是SingleTask同時執行個體已經存在,那麼應該是ActivityB移動到ActivityA之前,但是MainActivity也同時移到了ActivityA之前。MainActivity與ActivityA整個Task棧都移動了。按照Task的定義,ActivityStack棧裡是按照Task分組來管理Activity,那麼有可能APP之間的切換的排程機關會是Task。

(2)将MainActivity啟動模式變為:singleTask。這時如果我們從App2.ActivityB切換至App1.MainActivity會發什麼?

切換後任務棧:

Stack #10:
  Task id #289  //App1的Task棧移動到了App2的Task棧之前,但是這時情況是MainActivity之前的App1.ActivityA彈出了。Task棧下隻剩MainActivity
    TaskRecord{fd59417 #289 A=com.example.malingyi.testtask1 U=0 sz=1}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
      Hist #0: ActivityRecord{24d5faa u0 com.example.malingyi.testtask1/.MainActivity t289}
        Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
        ProcessRecord{a9ed :com.example.malingyi.testtask1/u0a60}
  Task id #290
    TaskRecord{d94004 #290 A=com.example.malingyi.testtask2 U=0 sz=2}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
      Hist #1: ActivityRecord{dd07174 u0 com.example.malingyi.testtask2/.ActivityB t290}
        Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
        ProcessRecord{c022 :com.example.malingyi.testtask2/u0a63}
      Hist #0: ActivityRecord{2c3fdf1 u0 com.example.malingyi.testtask2/.MainActivity t290}
        Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
        ProcessRecord{c022 :com.example.malingyi.testtask2/u0a63}
           

初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

操作後的棧:App2.ActivityB——>App1.ActivityA——>App1.MainActivity

MainActivity為SingleTask之後,由于它已經存在了一個執行個體,是以切換的時候會把App1的Task移動到App2的Task之前。然後根據SingleTask的規則,會将Task内在它之前的的Activity彈出,使得它置頂。

到了這裡,我們可以得出一個結論:

  • APP切換時,首先,會将切換的App所在的Task移動到最前面;然後,再使用LaunchModel的規則對Activity進行出棧入棧的操作。

然後再作出一個假設:

  • 我們在兩個程式之間的切換可能就是Task的切換?

情況三:多Task&SingleTask模式,App切換時Activity棧的情況

啟動模式&TaskAffinity:

App1、App2的MainActivity的LaunchModel = SingleTask, TaskAffinity = 包名;

App1中ActivityA: LaunchModel = SingleTask, TaskAffinity = com.TaskA;

App2中ActivityB: LaunchModel = SingleTask, TaskAffinity = com.TaskB;

初始化啟動順序:

Step1:啟動App1:MainActivity——>ActivityA ;

Step2:啟動App2:MainActivity——>ActivityB;

棧頂Activity:ActivityB

初始Activity棧:

App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

初始任務棧:

//我們可以看到,每一個Activity都在一個Task中,按照他們啟動的順序從上倒下。
  Stack #11:
    Task id #296 //App2.ActivityB的任務棧com.TaskB
      TaskRecord{a0 #296 A=com.TaskB U=0 sz=1}
      Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
        Hist #0: ActivityRecord{8c75fd1 u0 com.example.malingyi.testtask2/.ActivityB t296}
          Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
          ProcessRecord{f5bf6cc :com.example.malingyi.testtask2/u0a63}

    Task id #295 //App2.MainActivity的任務棧com.example.malingyi.testtask2
      TaskRecord{ #295 A=com.example.malingyi.testtask2 U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
        Hist #0: ActivityRecord{52f95ba u0 com.example.malingyi.testtask2/.MainActivity t295}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{f5bf6cc :com.example.malingyi.testtask2/u0a63}
    Task id #294  //App1.ActivityA的任務棧
      TaskRecord{da881e #294 A=com.TaskA U=0 sz=1}
      Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
        Hist #0: ActivityRecord{43ed667 u0 com.example.malingyi.testtask1/.ActivityA t294}
          Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
          ProcessRecord{d226d15 :com.example.malingyi.testtask1/u0a60}
    Task id #293   //App1.MainActivity的任務棧
      TaskRecord{b948ff #293 A=com.example.malingyi.testtask1 U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
        Hist #0: ActivityRecord{7669776 u0 com.example.malingyi.testtask1/.MainActivity t293}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{d226d15 :com.example.malingyi.testtask1/u0a60}

    //正在最前台的Activity
    mResumedActivity: ActivityRecord{c75fd1 u0 com.example.malingyi.testtask2/.ActivityB t296}
           

從上面的結果可以看出,由于給ActivityA、ActivityB指定了TaskAffinity、SingleTask,兩個MainActivity跟随App預設的任務棧,是以每一個Activity都有一個Task任務棧。但還是會按照程序将他們分為兩個APP。

注意看ProcessRecord字段會發現,App1.ActivityA和App1.MainActivity1是屬于同一個Process(d226d15 4068:com.example.malingyi.testtask1/u0a60)。而App2.ActivityB和App2.MainActivity2是屬于另一個

Process(f5bf6cc 4090:com.example.malingyi.testtask2/u0a6)。

(1)從App2.ActivatyB啟動App1.ActivityA

切換任務棧:

Stack #11:
    Task id #294 //App1.ActivityA所在的任務棧移到了最前面
      TaskRecord{da881e #294 A=com.TaskA U=0 sz=1}
      Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
        Hist #0: ActivityRecord{43ed667 u0 com.example.malingyi.testtask1/.ActivityA t294}
          Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
          ProcessRecord{d226d15 :com.example.malingyi.testtask1/u0a60}
    Task id #296 //App2.ActivityB所在的任務棧
      TaskRecord{a0 #296 A=com.TaskB U=0 sz=1}
      Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
        Hist #0: ActivityRecord{8c75fd1 u0 com.example.malingyi.testtask2/.ActivityB t296}
          Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
          ProcessRecord{f5bf6cc :com.example.malingyi.testtask2/u0a63}
    Task id #295 //App2.MainActivity所在的任務棧
      TaskRecord{ #295 A=com.example.malingyi.testtask2 U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
        Hist #0: ActivityRecord{52f95ba u0 com.example.malingyi.testtask2/.MainActivity t295}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{f5bf6cc :com.example.malingyi.testtask2/u0a63}
    Task id #293 //App1.MainActivity所在的任務棧
      TaskRecord{b948ff #293 A=com.example.malingyi.testtask1 U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
        Hist #0: ActivityRecord{7669776 u0 com.example.malingyi.testtask1/.MainActivity t293}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
          ProcessRecord{d226d15 :com.example.malingyi.testtask1/u0a60}

    Running activities (most recent first):
      TaskRecord{da881e #294 A=com.TaskA U=0 sz=1}
        Run #3: ActivityRecord{43ed667 u0 com.example.malingyi.testtask1/.ActivityA t294}
      TaskRecord{a0 #296 A=com.TaskB U=0 sz=1}
        Run #2: ActivityRecord{8c75fd1 u0 com.example.malingyi.testtask2/.ActivityB t296}
      TaskRecord{ #295 A=com.example.malingyi.testtask2 U=0 sz=1}
        Run #1: ActivityRecord{52f95ba u0 com.example.malingyi.testtask2/.MainActivity t295}
      TaskRecord{b948ff #293 A=com.example.malingyi.testtask1 U=0 sz=1}
        Run #0: ActivityRecord{7669776 u0 com.example.malingyi.testtask1/.MainActivity t293}

    mResumedActivity: ActivityRecord{ed667 u0 com.example.malingyi.testtask1/.ActivityA t294}
           

這裡我們看到,隻有Task#294(App1.ActivityA)移動到了Task#296(App2.ActivityB)之前,App1.MainActivity所在的Task#293,并沒有移動。

初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB

操作後的棧:App1.MainActivity——>App2.MainActivity——>App2.ActivityB——>App1.ActivityA

(2)從App2.ActivityB啟動App1.MainActivity

切換任務棧:

Stack #12:
   Task id #297  //App1.MainActivity所在的任務棧移到了最前面
     TaskRecord{b63e70 #297 A=com.example.malingyi.testtask1 U=0 sz=1}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
       Hist #0: ActivityRecord{f87eb51 u0 com.example.malingyi.testtask1/.MainActivity t297}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask1/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{d19c :com.example.malingyi.testtask1/u0a60}
   Task id #300  //App2.ActivityB所在的任務棧
     TaskRecord{d3ee5e9 #300 A=com.TaskB U=0 sz=1}
     Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
       Hist #0: ActivityRecord{3df6276 u0 com.example.malingyi.testtask2/.ActivityB t300}
         Intent { flg= cmp=com.example.malingyi.testtask2/.ActivityB }
         ProcessRecord{d16f7a5 :com.example.malingyi.testtask2/u0a63}
   Task id #299  //App2.MainActivity所在的任務棧
     TaskRecord{b126e #299 A=com.example.malingyi.testtask2 U=0 sz=1}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
       Hist #0: ActivityRecord{9778bab u0 com.example.malingyi.testtask2/.MainActivity t299}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg= cmp=com.example.malingyi.testtask2/.MainActivity bnds=[,][,] (has extras) }
         ProcessRecord{d16f7a5 :com.example.malingyi.testtask2/u0a63}
   Task id #298  //App1.ActivityA所在的任務棧
     TaskRecord{d0f #298 A=com.TaskA U=0 sz=1}
     Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
       Hist #0: ActivityRecord{f78be54 u0 com.example.malingyi.testtask1/.ActivityA t298}
         Intent { flg= cmp=com.example.malingyi.testtask1/.ActivityA }
         ProcessRecord{d19c :com.example.malingyi.testtask1/u0a60}
           

我重新啟動了一次APP,是以Task#ID改變了,但是他們初始的啟動順序沒變。

初始棧: App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB。

操作後的棧:App1.ActivityA——>App2.MainActivity——>App2.ActivityB——>App1.MainActivity

我們仍然看到,隻有Task#297 (App1.MainActivity)移動到了Task#300(App2.ActivityB)之前,App1.ActivityA所在的Task#298。

到了這裡,假設已經得到了實踐的驗證:

  • Android的APP切換,實際上是Activity以Task為機關來進行切換,将被選中的Activity所在的Task移動到Stack任務棧的最前端,然後在Task内部使用LaunchModel規則對Task内部的Activity進行操作。

三、總結

  • standard模式下,Activity會進入啟動它的Activity所在的Task棧中,這個結論對于在啟動其他App的Activity也成立。
  • LaunchModel的啟動規則,在跨App之間時啟動Activity同樣成立。
  • 在APP之間切換時。首先,會将切換的App所在的Task移動到最前面;然後,再使用LaunchModel的規則對Activity進行出棧入棧的操作。
  • Android的APP切換,實際上是以Task為機關來進行切換,将被選中的Activity所在的Task移動到Stack任務棧的最前端,然後在Task内部根據Activity的啟動模式,使用LaunchModel規則對Task内部的Activity進行操作。