Activity启动模式之SingleInstance

版权声明:原创作品,转载请注明原创链接地址! https://blog.csdn.net/wangxp423/article/details/83818150

启动模式系列之:Activity启动模式(Standrd和SingleTop)
启动模式系列之:Activity启动模式(SingleTask)
启动模式系列之:Activity启动模式(SingleInstance)

一,SingleInstance模式(单实例模式)

解释:在启动单实例模式的Activity时,系统为其创建一个耽误的任务栈,以后每次都会使用这个单例,直到这个单例被摧毁。

与栈内复用模式不同,栈内复用模式是指定taskAffinity属性,所创建的任务栈并不独享,仍可添加其他的Activity,而单实例模式所创建的任务栈只含有这个实例。所以说是真正的单例模式。

二,不设置taskAffinity属性。

操作示例:

MainActivity -> TestAActivity -> TestBActivity -> TestCActivity

adb记录:

  Stack #1:
    Task id #622
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
        Hist #2: ActivityRecord{d8c8249 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t622}
          Intent { flg=0x10400000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #1: ActivityRecord{1d98d9ee u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t622}
          Intent { cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #0: ActivityRecord{c7511f7 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t622}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
    Task id #623
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
      Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
        Hist #0: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}
          Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}

    Running activities (most recent first):
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
        Run #3: ActivityRecord{d8c8249 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t622}
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
        Run #2: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
        Run #1: ActivityRecord{1d98d9ee u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t622}
        Run #0: ActivityRecord{c7511f7 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t622}

    mResumedActivity: ActivityRecord{d8c8249 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t622}

首先,操作上此时的TestCActivity应该位于栈顶,从日志上也可以看出来,的确如此

再次,因为TestBActivity是SingleInstance模式,所以它在一个单独的任务栈中。从日志中可以看出来,TestBActivity确实在单独的任务栈TaskTecord中,但是这个任务栈的A值和系统默认任务栈的A值一样,都是包名,但是Task id不一样。这一点和我们的栈内复用设置taskAffinity不太一样,但是也是两个任务栈。

继续操作:

关闭TestCActivity

adb记录:

  Stack #1:
    Task id #622
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
        Hist #1: ActivityRecord{1d98d9ee u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t622}
          Intent { cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #0: ActivityRecord{c7511f7 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t622}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
    Task id #623
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
      Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
        Hist #0: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}
          Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}

    Running activities (most recent first):
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=2}
        Run #2: ActivityRecord{1d98d9ee u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t622}
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
        Run #1: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}
      TaskRecord{9d34a08 #622 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=2}
        Run #0: ActivityRecord{c7511f7 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t622}

    mResumedActivity: ActivityRecord{1d98d9ee u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t622}

从日志我们可以看出来,此时位于栈顶的的是TestActivity而不是,启动TestCActivity的TestBActivity。因为TestB位于自己的单独任务栈中,而MainActiity,TestAActivity,TestCActivity位于一个任务栈中。此时TestCActivity出栈,那么会切换到TestC所在的任务栈中,并显示这个栈中的栈顶Activity。

继续操作:

关闭TestAActivity,关闭MainActivity。

adb记录如下:

  Stack #1:
    Task id #623
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
      Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
        Hist #0: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}
          Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
          ProcessRecord{1d3f65bb 23767:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}

    Running activities (most recent first):
      TaskRecord{19b525a1 #623 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
        Run #0: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}

    mResumedActivity: ActivityRecord{1fb47bb4 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t623}

理论上,我们推出MainActivity页面应该退回到桌面,但是此时我们能看到。其实是回到了TestBActivity。

以上我们可以得到一个结论就是,当调用到单实例的任务栈,单实例的任务栈(唯一)在调起其他Activity(进入系统默认任务栈)。在回退的时候,会优先退出当前页面所在的任务栈,然后在退出单实例的任务栈。

第二种操作:

MainActivity -> TestAActivity -> TestBActivity -> TestCActivity -> TestBActivity

adb记录如下:

  Stack #1:
    Task id #627
      TaskRecord{3daa3fc3 #627 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
      Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
        Hist #0: ActivityRecord{3a2df81 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t627}
          Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
          ProcessRecord{3715cf72 28186:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
    Task id #626
      TaskRecord{34bcc040 #626 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity (has extras) }
        Hist #2: ActivityRecord{285247f3 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t626}
          Intent { flg=0x10400000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity }
          ProcessRecord{3715cf72 28186:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #1: ActivityRecord{19c94413 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t626}
          Intent { cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity }
          ProcessRecord{3715cf72 28186:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #0: ActivityRecord{29ed325 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t626}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity (has extras) }
          ProcessRecord{3715cf72 28186:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}

    Running activities (most recent first):
      TaskRecord{3daa3fc3 #627 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=1}
        Run #3: ActivityRecord{3a2df81 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t627}
      TaskRecord{34bcc040 #626 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
        Run #2: ActivityRecord{285247f3 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t626}
        Run #1: ActivityRecord{19c94413 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t626}
        Run #0: ActivityRecord{29ed325 u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t626}

    mResumedActivity: ActivityRecord{3a2df81 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t627}

从上面日志我们可以看到。TestBActivity位于栈顶。而从Activity的生命周期日志我们也应该知道。TestC再次调起TestB。此时TestB并没有重复创建,而是复用的他单独任务栈的中实例。并将该实例至于栈顶。而此时就再次出现了。应用默认任务栈和单实例任务栈的再次前后台切换。

三,设置taskAffinity属性。

操作记录:

MainActivity -> TestAActivity -> TestBActivity -> TestCActivity

adb记录如下:

 Stack #1:
    Task id #637
      TaskRecord{3de69dbf #637 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
        Hist #2: ActivityRecord{d69a4a6 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t637}
          Intent { flg=0x10400000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity }
          ProcessRecord{2c4937de 31071:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #1: ActivityRecord{2430b46 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t637}
          Intent { cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity }
          ProcessRecord{2c4937de 31071:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
        Hist #0: ActivityRecord{71407be u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t637}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity }
          ProcessRecord{2c4937de 31071:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}
    Task id #638
      TaskRecord{1ffb8c8c #638 A=org.wangchenlong.stack U=0 sz=1}
      Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
        Hist #0: ActivityRecord{9216615 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t638}
          Intent { flg=0x10000000 cmp=org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity }
          ProcessRecord{2c4937de 31071:org.wangchenlong.wcl_activity_launchmode_demo/u0a460}

    Running activities (most recent first):
      TaskRecord{3de69dbf #637 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
        Run #3: ActivityRecord{d69a4a6 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t637}
      TaskRecord{1ffb8c8c #638 A=org.wangchenlong.stack U=0 sz=1}
        Run #2: ActivityRecord{9216615 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestBActivity t638}
      TaskRecord{3de69dbf #637 A=org.wangchenlong.wcl_activity_launchmode_demo U=0 sz=3}
        Run #1: ActivityRecord{2430b46 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestAActivity t637}
        Run #0: ActivityRecord{71407be u0 org.wangchenlong.wcl_activity_launchmode_demo/.MainActivity t637}

    mResumedActivity: ActivityRecord{d69a4a6 u0 org.wangchenlong.wcl_activity_launchmode_demo/.TestCActivity t637}

从日志上我们可看出来,还是TestBActivity位于一个单独的任务栈,其他位于一个任务栈,不同于不设置taskAffinity属性的是。设置以后的TaskRecord的A值是我们设置的taskAffinity的值。其他跟默认不设置没有区别。有兴趣的同学可以试一下。

四,Activity启动模式总结

Android系统的任务栈体系分为三层:

  1. Stack,每一个应用属于一个Stack。一一对应
  2. TaskRecord,它含有一组Activity,通过单例模式SingleTask,SingleInstance支持创建多个TaskRecord。
  3. ActivityRecord,每一个Activity实例就是一个ActivityRecord。相同的支持存在多份实例。

启动模式本质上是为了避免相同Activity创建多个实例。避免系统资源的浪费。因此Android系统通过启动模式提供三种解决方案:

  1. SingleTop栈顶复用模式。当Activity位于栈顶时,直接复用。当位于栈中的时候,和标准模式一样,需要重复创建。
  2. SingleTask栈内复用模式。当Activity位于栈顶时,直接复用。当位于栈中的时候,清除其上的全部实例,直接复用,最终其就位于栈顶了。
  3. SingleInstance单实例模式,直接创建一个任务栈,无论Activity在什么位置。都会复用这个实例。

需要注意的是。SingleTask和SingleInstance都支持创建新的任务栈,这会涉及到前台任务栈和后台任务栈的关系。即一个Stack中有多个TaskRecord。

如果使用系统默认的后腿操作,即出栈操作,只有当前任务栈全部出栈,才会切换到其他任务栈,或者通过启动单实例模式的Activity才会触及切换任务栈。

另外还有一点,当单实例的任务栈位于系统默认任务栈上面的时候,此时如果点击手机Home键到桌面,然后再次点击应用图标,系统可能会认为是再次启动,直接切换到系统默认任务栈,此时显示的是系统任务栈栈顶的那个页面,而在退出这个栈所有的页面以后,并没有自动切换到单实例的任务栈,而是直接到桌面了。单实例的任务栈此时还在内存中。如果再次启动应用调用单实例的页面,会复用该页面并切换到单实例的任务栈中。

Demo下载:https://download.csdn.net/download/wangxp423/10767068

参考:《高级Android开发强化实战》

推荐:https://github.com/wangxp423 喜欢的小伙伴点一下 Star

猜你喜欢

转载自blog.csdn.net/wangxp423/article/details/83818150