Android Activity 的四种启动模式

Android Activity 的四种启动模式

一 . Android 任务栈

      一个 Android 应用程序功能通常会被拆分为多个 Activity ,各个 Activity 之间通过 Intent 进行连接,而 Android 系统,通过栈结构来保存整个 App 的 Activity ,栈底的元素师整个任务栈的发起者。一个合理的任务调度栈不仅是性能的保证,更是提供性能的基础。

     当一个 App 启动时,如果当前环境中不存在该 App 的任务栈,那么系统就会创建一个任务栈。此后,这个 App 所启动的 Activity 都将在这个任务栈中被管理,这个栈也被称为一个 Task ,即表示若干个 Activity 的集合,它们组合在一起形成一个 Task 。另外,需要特别注意的是,一个 Task 中的 Activity 可以来自不同的 App ,同一个 App 的 Activity 也可能不在一个 Task 中。

      由于栈是一种后进先出( Last In First Out )的线性表。根据 Activity 在当前任务栈的位置来决定该 Activity 的状态。一般情况下的 Android 任务栈是这样的:当一个 Activity 启动了另一个 Activity 的时候,新启动的 Activity 就会位于任务栈的栈顶位置,并处于活动状态;当用户按下返回键或者调用 finish ( ) 方法时,系统会移除栈顶的 Activity ,让后面的 Activity 恢复活动状态。当然,这是系统默认的启动模式。Android 系统还提供了别的启动模式来满足项目的各种不同需求,如:singleTop , singleTask , singleInstance 。开发者通过在 AndroidMainifest 文件中的属性 android : launchMode 来设置启动模式,或者是通过 Intent 的 flag 来设置。

目前 Android Activity 的启动模式一共四种,分别是:

  1. standard : 标准模式
  2. singleTop : 栈顶复用模式
  3. singleTask :栈内服用模式
  4. singleInstance :单实例模式

这四种启动模式都具有不同的功能,下面我们一起来一一学习。


二 . standard ( 标准模式 )

      standard 是系统默认的启动模式,也就是在不进行显式指定 Activity 的启动模式,所有的 Activity 都会自动使用这种启动模式。这种模式的特点是:每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。

      从 Activity 生命周期角度分析:这种启动模式下,被创建的实例的生命周期完全符合一般情况下 Activity 的生命周期,也就是它的 onCreate ( ) , onStart ( ) , onResume ( ) 方法依次会被调用。这是一种典型的多实例实现。

      从 Activity 任务栈的角度分析:每当启动一个新的 Activity 它就会在任务栈中入栈,并处于栈顶的位置。一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈,在这种启动模式下,哪个Activity 启动了这个 Activity ,该 Activity 就运行在启动它的那个 Activity 所在的栈中。比如:ActivityA 启动了 ActivityB ( B 是标准模式 ) ,那么 ActivityB 就会进入到 ActivityA 所在的栈中。

下面给出了 ActivityA 中 onCreate ( ) 方法的代码,如下所示:  

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("ActivityA",this.toString());
    setContentView(R.layout.activity_a);
    Button btn1= (Button) findViewById(R.id.btn1);
    btn1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent=new Intent(ActivityA.this,ActivityA.class);
            startActivity(intent);
        }
    });
}

     为了说明 standard 启动模式的原理,列举了一个没有实际意义的例子,即在 ActivityA 的基础上启动 ActivityA ,并还在 onCreate ( ) 方法中添加了一行 Log 打印当前活动的实例的信息。运行程序,然后在 ActivityA 界面连续点击两次按钮,可以看到 logcat 中打印信息如下:


      从打印信息中可以看出,每点击一次按钮就会创建出一个新的 ActivityA 实例。此时返回栈中也会存在3个 ActivityA 的实例。因此需要连续按3次 Back 键才能退出程序。

下面是上述代码 standard 模式的原理示意图:


2.1 standard 模式示意图



三 . singleTop :栈顶复用模式

      在这种模式下,可以根据 Activity 在任务栈中的位置而确定是否为新 Activity 创建新的实例,如下图所示:


3.1 singleTop 模式分析图

      在这种模式下,针对系统是否为新 Activity 创建新的实例的情况,可以大致分为三种情况:第一种是新 Activity 的实例不在任务栈,则系统会为该新 Activity 创建新的实例,这情况和 standard 模式大致相同;第二种是新 Activity 的实例在任务栈里,并且还是位于任务栈的栈顶,那么该新 Activity 不会被重新创建,同时它的 onNewIntent ( ) 方法会被调用,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,这个新 Activity 的 onCreate ( ) 、 onstart ( ) 不会被系统调用,因为它并没有发生变化;第三种是第二种的另一个分支,也就是新 Activity 的实例已经存在于任务栈中,但不是位于栈顶,那么新 Activity 仍然会重新创建。举个例子,如果当前任务栈中有 A、B、C、D 四个 Activity ,A 位于栈底,D 位于栈顶,这个时候如果要再次启动 D ,如果 D 的启动模式是 singleTop ,那么栈内的情况为 ABCD ;如果 D 的启动模式为 standard ,那么再次启动 D 的话,栈内的情况为 ABCDD 。下面来看这例子 Activity 任务栈中的情况:



四 . singleTask :栈内复用模式

      singleTask 模式与 singleTop 模式类似,只不过 singleTop 模式是检测栈顶元素是否是需要启动的 Activity ,而 singleTask 是检测整个任务栈中是否存在当前需要启动的 Activity 。只要 Activity 在任务栈中,那么多次启动此 Activity 都不会重新创建实例,系统会回调该 Activity 中的 onNewIntent ( ) 方法。


4.1 singleTask任务栈


下面分多种情况分析:

  1. 系统首先会检测是否存在该 Activity 想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建该 Activity 的实例并把该实例放进栈中。
  2. 如果该 Activity 想要的任务栈存在,那么还会根据目标 Activity 的所在情况分为以下几种情况来分析:

  • 如果将要启动的目标 Activity 不存在,系统将会创建目标 Activity 的实例,并将它加入 Task 栈顶。
  • 如果将要启动的目标 Activity 已经位于 Task 栈顶,此时与 singleTop 模式的行为相同。
  • 如果将要启动的目标 Activity 已经存在、但没有位于 Task 栈顶,系统将会把该 Activity 上面的所有 Activity 移出 Task 栈,从而使得目标 Activity 转入栈顶。

下面举几个例子,帮助更进一步了解 singleTask 模式。

     1 . 如果当前任务栈 S1 中的情况为 ABC ,这个时候 ActivityD 以 singleTask 模式请求启动,它所需要的任务栈是 S2,由于 S2 和 D 的实例都不存在,所以系统就会先创建任务栈s2,然后再创建D的实例并将D的实例放入任务栈s2中。

    2 . 假设 D 所需的任务栈为 S1 ,其他情况如上面例子1 所示,那么由于 S1 已经存在,所以系统会直接创建实例 D 并将其入栈到 S1 。

   3 .如果 D 所需的任务栈 S1 ,并且当前任务栈 S1 的情况为 ADBC ,根据栈内复用的原则,此时 D 不会重新创建,系统会把 D 切换到栈顶并调用它的 onNewIntent ( ) 方法,同时由于 singleTask 默认具有 clearTop 的效果,会导致栈内所有在 D 上面的 Activity 全部出栈,于是最终 S1 中的情况为 AD 。 

4 . 假设目前有2个任务栈,前台任务栈的情况为 AB ,而后台任务栈的情况为 CD ,假设 CD 的启动模式均为 singleTask 。现在请求启动 D ,那么整个后台任务栈都会被切换到前台,这个时候整个后退列表变成了 ABCD 。当用户按 back 键的时候,列表中的 Activity 会一一出栈,如下图4.1所示;如果不是请求启动 D 而是启动 C ,那么情况就如图4.2所示了。


                   4.1  任务栈    



                                                                                       4.2  任务栈 


五 . singleInstance : 单实例模式

      这种模式下,系统保证无论从哪个 Task 中启动目标 Activity ,只会创建一个目标 Activity 实例,并会使用一个全新的 Task 栈来装载该 Activity 实例。

      当系统采用 singleInstance 模式启动目标 Activity 时,可分为如下两种情况:

  • 如果将要启动的目标 Activity 不存在,系统会先创建一个全新的 Task ,再创建目标 Activity 的实例,并将它加入新的 Task 的栈顶。
  • 如果将要启动的目标 Activity 已经存在,无论它位于哪个应用程序中,也无论它位于哪个 Task 中,系统将会把该 Activity 所在的 Task 转到前台,从而使用该 Activity 显示出来。

     需要指出的是,采用 singleInstance 模式加载 Activity 总是位于 Task 栈顶,采用 singleInstance 模式加载 Activity 所在的 Task 只包含该 Activity 。


六 . Activity 的 Flags

      系统提供了两种方式来设置一个 Activity 的启动模式,下面介绍第二种通过设置 Intent 的 Flag 来设置一个 Activity 的启动模式。其中,Activity 的Flags 有很多,下面只要分析一些比较常用的标记为。在大多数情况下,我们不需要为 Activity 指定标记为,因此,对待标记位达到理解即可。同时,在使用标记位的时候,要注意有些标记位是系统内部使用的,应用程序不需要手动设置这些标记位,以防出现问题。

  • FLAG_ACTIVITY_NEW_TASK

      这个标记位的作用与指定 android:launchMode=“singleTask”效果相同。

  • FLAG_ACTIVITY_SINGLE_TOP

      这个标记位的作用与指定 android:launchMode=“singleTop”效果相同。

  • FLAG_ACTIVITY_CLEAR_TOP

     具有此标记的 Activity ,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。这个标记位一般会和 singleTask 启动模式一起出现,在这种情况下,被启动 Activity 的实例如果已经存在,那么系统就会调用它的 onNewIntent ( ) 方法。如果被启动的 Activity 采用 standard 模式启动,那么它连同它之上的 Activity 都要出栈,系统会创建新的 Activity 实例并放入栈顶。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

     使用这种模式启动 Activity ,当该 Activity 启动其他 Activity 后,该 Activity 就消失了,不会保留在 Activity 栈中,等同与在 XML 中指定 Activity 的属性 android:excludeFromRecents=“ true ” 。例如 AB,B 中以这种模式启动 C ,C 再启动 D ,则当前 Activity 栈为 ABD 。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值