Activity启动模式及标记位

Activity启动模式

在说activity启动模式之前,我们要先了解activity栈的概念。activity任务栈是一个“后进先出”的栈结构。即启动一个新activity实例时会将其压入栈顶,当该activity按返回键退出时,其实例会从任务栈中出栈。任务栈分为前台任务栈和后台任务栈,后台任务栈中的activity位于暂停状态,用户可以通过切换将后台任务栈再次调到前台。

activity的启动模式就是配合栈的工作原理,来满足日常的业务需要。activity启动的模式有四种:standard、singleTop、singleTask和singleInstance。standard就是activity默认的启动模式。

standard:标准模式(默认模式)

这种模式下的activity每次启动都会创建一个新的实例,并且不管该实例是否在任务栈内存在都会压栈。如果activityA和activityB都是标准模式,activityA启动了activityB,这时候栈顶是activityB,下面是activityA。

标准模式的activity默认会进入启动它的activity所属的任务栈中,非activity类型的Context若要启动该activity,需要加上标记位FLAG_ACTIVITY_NEW_TASK,即重新为其创建一个新的任务栈。此标志位的启动模式实际上是以singleTask模式启动的。(后续会解释,这里先跳过标记位知识点)

命令行查看栈内activity列表信息

例:在同一APP内且没有标记位情况下,执行跳转activityA——activityB——activityC——activityA,他们都是标准模式。理论上栈内应为ABCA。

命令行执行:

 adb shell dumpsys activity

命令行查询栈信息时里面的信息非常多且杂,这里主要看
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
该行下面的信息即可,即 Hist #3:—— Hist #2:—— Hist #1:—— Hist #0:,栈内从上到下的的显示顺序,Hist #3位于栈顶。

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #319
      TaskRecord{22fe5578 #319 A=com.jzf.myactivity U=0 sz=4}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.jzf.myactivity/.ActivityA }
        Hist #3: ActivityRecord{38af6616 u0 com.jzf.myactivity/.ActivityA t319}
          Intent { cmp=com.jzf.myactivity/.ActivityA }
          ProcessRecord{37252451 3045:com.jzf.myactivity/u0a58}
        Hist #2: ActivityRecord{29295492 u0 com.jzf.myactivity/.ActivityC t319}
          Intent { cmp=com.jzf.myactivity/.ActivityC }
        Hist #1: ActivityRecord{4dcc45c u0 com.jzf.myactivity/.ActivityB t319}
          Intent { cmp=com.jzf.myactivity/.ActivityB }
        Hist #0: ActivityRecord{2bc3c1f6 u0 com.jzf.myactivity/.ActivityA t319}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.jzf.myactivity/.ActivityA }

    Running activities (most recent first):
      TaskRecord{22fe5578 #319 A=com.jzf.myactivity U=0 sz=4}
        Run #0: ActivityRecord{38af6616 u0 com.jzf.myactivity/.ActivityA t319}

    mResumedActivity: ActivityRecord{38af6616 u0 com.jzf.myactivity/.ActivityA t319}

也能从 Running activities (most recent first):该行下面看到该栈内的activity数量sz=4,以及位于栈顶的activityA。

singleTask:栈内复用模式

这是一种单实例模式,只要该模式的activity在一个栈中存在,多次启动此activity都不会创建实例。singleTask模式默认具有clearTop效果,会导致栈内所有在此activity上的所有activity全部出栈。这种模式下,系统会回调此activity的onNewIntent方法,不会重新执行该activity的onCreate和onStart方法。

例:在同一APP内且没有标记位情况下,执行跳转activityA——activityB——activityC——activityB,activityA和activityC是标准模式,activityB是singleTask模式。理论情况下结果应该是AB,B位于栈顶。

activityC跳转到activityB的log日志如下:

D/ActivityC: onPause
D/ActivityB: onNewIntent
D/ActivityB: onRestart
D/ActivityB: onStart
D/ActivityB: onResume
D/ActivityC: onStop
D/ActivityC: onDestroy
D/ActivityC: ————————————————

命令行查询栈部分信息如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #321
      TaskRecord{280e2df3 #321 A=com.jzf.myactivity U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.jzf.myactivity/.ActivityA }
        Hist #1: ActivityRecord{2beb98ab u0 com.jzf.myactivity/.ActivityB t321}
          Intent { flg=0x10000000 cmp=com.jzf.myactivity/.ActivityB }
          ProcessRecord{1cfbcab0 3775:com.jzf.myactivity/u0a58}
        Hist #0: ActivityRecord{1b45261d u0 com.jzf.myactivity/.ActivityA t321}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.jzf.myactivity/.ActivityA }

    Running activities (most recent first):
      TaskRecord{280e2df3 #321 A=com.jzf.myactivity U=0 sz=2}
        Run #0: ActivityRecord{2beb98ab u0 com.jzf.myactivity/.ActivityB t321}

    mResumedActivity: ActivityRecord{2beb98ab u0 com.jzf.myactivity/.ActivityB t321}

如上所述,Hist #1: 是ActivityB,Hist #0:是ActivityA,整个任务栈有两个activity,ActivityB位于栈顶。
这就解释了activityA——activityB——activityC——activityB,当activityC——activityB时会复用栈内已有的activityB实例,并清空原先位于上面的activityC。

singleTop:栈顶复用模式

如果此模式的activity位于任务栈的栈顶(复用的前提必须满足这个条件哦~),那么此activity不会被重新创建,同时它的onNewIntent方法会被回调。需要注意的是该activity的onCreate,onStart不会被系统调用,因为它并没有发生改变。

singleInstance:单实例模式

简单理解就是这是一种加强型的singleTask模式,除了具备singleTask的所有特性外,还有一点是具备此模式的activity只能单独位于一个任务栈中。由于具备singleTask的栈内复用特性,后续的启动该activity均不会创建新的activity,除非这个任务栈被销毁了。

常用标记位

activity的启动,通常是在AndroidMenifest.xml文件中设置启动模式,但有些时候也会用到标记位。这里简单列举下常用的标记位及其用法,其余的各位完全可以在源码中了解的~

注意:加标记位的启动模式优先级比在AndroidMenifest.xml文件中指定的启动模式。

FLAG_ACTIVITY_NEW_TASK

此标记位的意义在于,在Activity上下文之外启动Activity需要给Intent设置FLAG_ACTIVITY_NEW_TASK标志,系统会为这个Activity指定或分配一个任务栈。
此模式为activity指定“singleTask”启动模式,其效果和在AndroidMenifest.xml文件中指定该启动模式相同。设置此状态,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即TaskAffinity,注意同一个应用程序中的activity的亲和性一样)。如果有,就直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变;如果没有,则新建一个栈来存放被启动的activity。

FLAG_ACTIVITY_CLEAR_TOP

清除包含此Activity的Task中位于该Activity实例之上的其他Activity实例。

案例:activityA——activityB——activityC——activityB,在启动activityB的时候单独加上

 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

在activityC启动activityB时候打印部分log日志如下:

D/ActivityC: onPause
D/ActivityB: onDestroy
D/ActivityB: ————————————————
D/ActivityB: onCreate
D/ActivityB: onStart
D/ActivityB: onResume
D/ActivityC: onStop
D/ActivityC: onDestroy
D/ActivityC: ————————————————

FLAG_ACTIVITY_SINGLE_TOP

与launchMode=”singleTop”一样的效果。

若FLAG_ACTIVITY_CLEAR_TOP配合FLAG_ACTIVITY_SINGLE_TOP使用,则B不会销毁只销毁B以上实例,然后B 执行onNewIntent -> onStart。

案例:activityA——activityB——activityC——activityB,在启动activityB的时候加上两个标记位,在activityC启动activityB时候打印部分log日志如下:

D/ActivityC: onPause
D/ActivityB: onNewIntent
D/ActivityB: onRestart
D/ActivityB: onStart
D/ActivityB: onResume
D/ActivityC: onStop
D/ActivityC: onDestroy
D/ActivityC: ————————————————

你可能感兴趣的:(android基础)