美文网首页
Activity的四种启动模式

Activity的四种启动模式

作者: 维一hw | 来源:发表于2017-07-28 13:49 被阅读0次

Activity四种启动模式

这部分应该是最最基础的了,但是还是有很多细节需要把握,不只是表面的知识点。

  • 1 Activity的管理是采用任务栈的形式
  • 2 任务栈采用“后进先出”的栈结构
  • 3 每按一次Back键,就有一个Activity出栈
image.png
  • 标准模式(standard)
    每启动一次Activity,就会创建一个新的Activity实例并置于栈顶谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。也就是说在ActivityA中启动了ActivityB那么ActivityB就在ActivityA的栈中
image.png
  • 单例模式(singleInstance)
  1. 作为栈内复用模式(singleTask)的加强版
  2. 打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入新栈中
  3. 一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例
  4. 使用场景:多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。
    四种启动模式图解
image.png
四种启动模式的区别
  • 决定打开的任务栈
    standard、singleTop启动模式的Activity的目标任务栈,和收到Intent的发送者在同一个任务栈内。
    singleTask启动模式打开的任务栈由参数TaskAffinity决定。
    singleInstance启动模式总是新建任务栈,不会被启动到一个其他任务栈里。
  • 是否允许多个相同的Activity实例
    standard、singleTop启动模式中,同一个Activity可以被实例化多次,并且存在于不同的任务栈中,且一个任务栈可以包括同一个Activity的多个实例;
    singleTask、singleInstance启动模式则限制只生成一个实例。
  • 是否允许不同的Activity实例存在于同一个任务栈内
    singleInstance启动模式独占一个任务栈,其它Activity实例不能存在于该任务栈里。
    另外三种模式,则可以和其它Activity实例共存于一个任务栈。
  • 是否每次都生成新实例
    standard模式:每次都生成新实例。
    singleTop模式:若启动的Activity不在栈顶,则生成新实例;
    singleInstance模式:所在栈的唯一Activity实例,只会实例化一次,以后每次都被重用。
    singleTask模式:若启动的Activity不在栈内,则生成新实例;
    启动模式的设置
    启动模式有两种设置方式:
  • 在AndroidMainifest设置
  • 通过Intent设置标志位
    1.在AndroidMainifest中设置
image.png

2.通过Intent设置标志位

image.png image.png
二者设置的区别
  • Intent设置方式比Manifest设置方式的优先级要高,即以前者为准
  • 限定范围不同
    Manifest设置方式无法设定FLAG_ACTIVITY_CLEAR_TOP标识;Intent设置方式无法设置单例模式(singleInstance)
    介绍一下任务栈:
    (1)程序打开时就创建了一个任务栈, 用于存储当前程序的activity,所有的activity属于一个任务栈。
    (2)一个任务栈包含了一个activity的集合,去有序的选择哪一个activity和用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
    (3)任务栈可以移动到后台,并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务,而且还不丢失它们状态信息。
    (4)退出应用程序时:当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。
    任务栈的缺点:
    (1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用户体验差,需要点击多次返回才可以把程序退出了。
    (2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余,重复数据太多,会导致内存溢出的问题(OOM)。
    为了解决任务栈的缺点,我们引入了启动模式。
    Standard
       默认模式 v,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
      若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上…….
      点back键会依照栈顺序依次退出。
    singleTop
      可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
    例如:
      若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
      若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
      若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。
    singleTask
       只有一个实例。在同一个应用程序中启动的它时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。
       如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
    例如:
       若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样因为singleTask会把task中在其之上的其它Activity destory掉。
    操作:C1->C2 C1->C2->C3 C1->C2->C3->C2 C1->C2->C3->C2->C3->C1 C1->C2->C3->C2->C3->C1-C2
    实际:C1->C2 C1->C2->C3 C1->C2 C1->C2->C3->C1 C1->C2
      若是别的应用程序打开C2,则会新启一个task
      如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C1、C3的taskId仍为201。
    注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。
    singleInstance
      只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
    例如:
      加载该Activity时如果没有实例化,他会创建新的Task后,实例化入栈,如果已经存在,直接调用 onNewIntent,该Activity的Task中不允许启动其它的Activity,任何从该Activity启动的其他Activity都将被放到其他task中,先检查是否有本应用的task,没有的话就创建。
      程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。
    singleInstance附加解释:
       这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
       我们修改MainActivity的launchMode=”standard”,SecondActivity的launchMode=”singleInstance”,由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码:
    TextView textview=(TextView)findViewById(R.id.tv); textview.setText("current tesk id"+this.getTaskId());
image.png image.png

  我们发现这两个Activity实例分别被放置在不同的栈结构中,关于singleInstance的原理图如下

image.png

   上半部分图我们看到从MainActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到MainActivity,这个时候系统会在原始栈结构中生成一个MainActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到MainActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。

相关文章

网友评论

      本文标题:Activity的四种启动模式

      本文链接:https://www.haomeiwen.com/subject/jxixlxtx.html