温故知新—Activity的五种启动模式

这篇具有很好参考价值的文章主要介绍了温故知新—Activity的五种启动模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前因后果

这两天遇到了一个 bug ,说是应用打开一个二级页面,然后直接回到桌面,并不是杀掉应用,只是回到桌面,再次打开的时候没有回到那个二级页面,而是回到了首页。

看到这里,很多人大概都知道是什么原因了,没错,就是 Activity 的启动模式设置为了 singleTask 而导致的问题,本来觉得自己基础还凑合,但这个问题真没有想到过,所以,今天来重新过一遍 Activity 的启动模式。

开整

首先大家都知道 Android 中使用任务栈来存储创建的 Activity ,栈是先进后出,这里的任务栈当然也一样,最先进入的页面在栈的最底部,当按返回键的时候,每按一次,一个 Activity 出栈,直到栈空为止,当栈中没有 Activity 时,系统就会回收此任务栈。

任务栈

那么问题来了,什么是任务栈呢?

一个应用默认只有一个任务栈,当然也可以有多个任务栈,某信中就有。查看任务栈其实很简单,在 Android 设备中进入多任务就能看到,来看下某信的截图:

温故知新—Activity的五种启动模式

上图中的某信就有多个任务栈。

那么为啥会有启动模式一说呢???因为如果多次启动同一个 Activity 的时候,不管任务栈中是否存在这个 Activity,都会创建多个 Activity,而且还浪费了内存空间,所以 Google 为 Activity 的创建提供了几种启动模式。

之前的版本中是四种启动模式,但在 Android12( S 31)之后的版本则修改为了五种启动模式,下面咱们来一个一个看。

准备工作

先来做下准备工作,创建一个空的应用,然后再创建两个 Activity 并打印它们的生命周期:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_two)
    Log.e(TAG, "onCreate: ")
}
​
override fun onStart() {
    super.onStart()
    Log.e(TAG, "onStart: ")
}
​
override fun onResume() {
    super.onResume()
    Log.e(TAG, "onResume: ")
}
​
override fun onPause() {
    super.onPause()
    Log.e(TAG, "onPause: ")
}
​
override fun onStop() {
    super.onStop()
    Log.e(TAG, "onStop: ")
}
​
override fun onDestroy() {
    super.onDestroy()
    Log.e(TAG, "onDestroy: ")
}

标准模式——standard

这个启动模式是最常见的,Activity 默认就是此启动模式。每启动一次 Activity,就会创建一个新 Activity 实例并置于栈顶。谁启动了这个 Activity,那么这个 Activity 就运行在启动它的那个 Activity 所在的栈中。

其实后面这句话挺重要,之前学习的时候并不是太理解这句话,但也是在不久前遇到了一个问题让我重新理解了:Android 中有多窗口模式,这个问题是在多窗口模式下发现的,我们应用中有个地方会调用设置中的页面来选择声音,在正常模式下是没有问题的,但是多窗口模式下就会重新启动一个任务栈,但我们系统中限制多窗口模式下只能有一个应用在前台,结果我们自己的应用被干掉了。。。大家一定引以为戒,知识点的每一句话都有可能有用!

下面咱们来测试下标准模式,先一步一步来,先从第一个页面跳转到第二个页面,看下 log:

E/MainActivity: onCreate: 
E/MainActivity: onStart: 
E/MainActivity: onResume: 
E/MainActivity: onPause: 
E/TwoActivity: onCreate: 
E/TwoActivity: onStart: 
E/TwoActivity: onResume: 
E/MainActivity: onStop: 

没什么问题,和预想的一致,然后回到桌面再打开应用,看下 log:

E/TwoActivity: onPause: 
E/TwoActivity: onStop: 
E/TwoActivity: onStart: 
E/TwoActivity: onResume: 

嗯,没问题,现在任务栈里有两个 Activity,点击返回键依次退出再来看下 log:

E/TwoActivity: onPause: 
E/MainActivity: onStart: 
E/MainActivity: onResume: 
E/TwoActivity: onStop: 
E/TwoActivity: onDestroy: 
E/MainActivity: onPause: 
E/MainActivity: onStop: 

从第二个 Activity 回到第一个 Activity 可以理解,但是大家有没有发现第一个 Activity 并没有走 onDestroy ,这里引用下一个厉害的大哥文章中的描述吧:

Android 12 以前,当我们处于 Root Activity 时,点击返回键时,应用返回桌面, Activity 执行 onDestroy,程序结束。 Android 12 起同样场景下 Activity 只会 onStop,不再执行 onDestroy。

想看大哥原文的可以点击:有关 Android12 中 Activity 生命周期的变化

到这里标准模式就差不多了,因为这是默认的启动模式,大家使用也最频繁,也就不再啰嗦。

栈顶模式——singleTop

栈顶模式其实很好理解,如果栈顶存在该activity的实例,则复用,不存在新建放入栈顶,它的表现几乎和 上面刚说的标准模式一模一样,栈顶模式的 Activity 实例可以无限多,唯一的区别是如果在栈顶已经有一个相同类型的 Activity 实例,那么 Intent 则不会再去创建一个 Activity,而是通过 onNewIntent() 发送到现有的Activity。

比如应用现在在一个详情页面,而且这个页面启动模式为栈顶模式,这个时候来了一个通知,点击通知正好要跳转到详情页面,那么这个时候任务栈就不会为这个 Activity 再创建一个实例而用已经在栈顶的之前创建好的 Activity 实例。

栈内复用——singleTask

这个模式之前真的没有理解透彻,之前我理解的就是如果栈内存在该 Activity 的实例则进行复用,如果不存在则创建。

接下来将刚才的 Demo 中的主 Activity 的启动模式改为栈内复用,先来看下启动应用后点击跳转到第二个 Activity 的 log:

E/MainActivity: onCreate: 
E/MainActivity: onStart: 
E/MainActivity: onResume: 
E/MainActivity: onPause: 
E/TwoActivity: onCreate: 
E/TwoActivity: onStart: 
E/TwoActivity: onResume: 
E/MainActivity: onStop: 

目前来看还是比较正常的,接下来直接回到桌面,再来看下 log:

E/TwoActivity: onPause: 
E/TwoActivity: onStop: 

也还对着呢,然后再次打开应用再看 log:

E/TwoActivity: onDestroy: 
E/MainActivity: onStart: 
E/MainActivity: onResume: 

是不是不对了,我本来想让应用回到第二个 Activity,但为什么第二个 Activity 直接销毁了?

其实栈内复用中还有一点要注意,也正是我忽略的重要一点:栈内复用模式会将该实例上边的 Activity 全部出栈,将该实例置于栈顶,这也就是出现文章开头我说的那个问题的根本原因。

单例模式——singleInstance

单例模式,顾名思义,就是新开一个任务栈,该栈内只存放当前实例。比如说项目中语音通话功能,来电显示页面采用的就可以采用单例模式进行处理。

当然还有别的方法来新开任务栈,比如说启动 Activity 的时候加上 FLAG_ACTIVITY_NEW_TASK ,也会开启一个新的任务栈。

这里需要注意,即使将 Activity 的启动模式设置为单例模式或者添加了 flag,也不会出现像上面某信那种效果,因为 Activity 的 taskAffinity 是一样的,但如果将 Activity 的 taskAffinity 修改下,就可以出现类似于上面某信的效果,如下图所示:

温故知新—Activity的五种启动模式

单例任务模式——singleInstancePerTask

其实这个单例任务模式是我自己编的😂,这个和上面所说的单例模式基本一致,只不过会为启动的 Activity 新建任务栈,而不需要像上面说的单例模式那样修改 taskAffinity。

打完收工

到这里为止基本把 Android 的启动模式都说了一遍,为自己做个总结,以后不能再出现这种错误了。

如果能帮助到大家的话最好不过了,看到这里麻烦点点赞关注下,感激不尽!!!

就这样。文章来源地址https://www.toymoban.com/news/detail-489705.html

到了这里,关于温故知新—Activity的五种启动模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(36)
  • Linux学习第31天:Linux MISC 驱动实验:温故知新

    Linux版本号4.1.15   芯片I.MX6ULL                                     大叔学Linux    品人间百味  思文短情长           学习是一个不断重复的过程。只有不断的使用、修正,才能越记越牢。将学习到的新的知识点应用到以往的项目经验中,才能不断提升自我,长此以往

    2024年02月06日
    浏览(37)
  • .net 温故知新【17】:Asp.Net Core WebAPI 中间件

    到这篇文章为止,关于.NET \\\"温故知新\\\"系列的基础知识就完结了,从这一系列的系统回顾和再学习,对于.NET core、ASP.NET CORE又有了一个新的认识。 不光是从使用,还包括这些知识点的原理,虽然深入原理谈不上,但对于日常使用也够了,我想的是知其然,知其所以然。 在实际

    2024年01月18日
    浏览(39)
  • .net 温故知新【11】:Asp.Net Core WebAPI 入门使用及介绍

    在Asp.Net Core 上面由于现在前后端分离已经是趋势,所以asp.net core MVC用的没有那么多,主要以WebApi作为学习目标。 我使用的是VS2022, .Net 7版本。 在创建界面有几项配置: 配置Https 启用Docker 使用控制器 启用OpenAPI支持 不使用顶级语句 其中配置Https 是WebApi是否使用https协议,启

    2024年02月07日
    浏览(30)
  • java -jar启动的五种方式(包括后台启动)

    1、用java -jar xxx.jar 点击回车就会启动成功,但是当退出或者关闭远程工具就会把进程关闭 以上就是启动的项目Java -jar xxx.jar 但是点击过Ctl+c或者把此窗口关闭 就会杀死进程那么此程序就会关闭 2、命令:java -jar xxx.jar 此语句比第一个命令多一个符号,但是Ctrl+c或者关闭窗口后

    2024年02月11日
    浏览(26)
  • 【SpringBoot】 启动后执行方法的五种方式

    在 SpringBoot 工程 启动后, 执行方法的五种方式: 1、实现 CommandLineRunner 接口 项目初始化完毕后,才会调用方法,提供服务 2、实现 ApplicationRunner 接口 同 CommandLineRunner。只是传参格式不一样。CommandLineRunner:没有任何限制;ApplicationRunner:key-value 3、实现 ApplicationListener 接口

    2023年04月08日
    浏览(34)
  • 温故而知新-JVM垃圾收集器

    标记-清除 复制算法 标记-整理 现在垃圾收集器均采用分代收集策略,新生代由于98%的对象都是朝生夕死,复制算法更合适,只复制还存活的对象,工作量小,所以效率高。显然复制算法不适合老年代,因为老年代中的对象大部分是大对象,且长时间存活,复制算法效率太低

    2024年02月15日
    浏览(47)
  • 【温故而知新】HTML5 WebSocket

    HTML5是HTML的最新版本,它引入了许多新的元素和功能,以适应现代网页开发的需求。以下是HTML5的一些主要特点: 新增语义元素 :HTML5引入了许多新的语义元素,如 header、footer、article、section 等,这些元素有助于提高网页的结构化和可访问性。 媒体支持 :HTML5引入了 audio 和

    2024年01月18日
    浏览(33)
  • 【温故而知新】JavaScript类、类继承、静态方法

    JavaScript是一种广泛使用的编程语言,主要用于Web开发。它是一种脚本语言,这意味着它不需要像编译语言那样预先编译,而是在运行时解释和执行。JavaScript可以直接在浏览器中运行,这使得它在前端开发中特别重要,可以用于动态生成和更改网页内容、响应用户交互、发送

    2024年01月22日
    浏览(33)
  • 【温故而知新】JavaScript的继承方式有那些

    JavaScript使用原型链来实现继承。每个JavaScript对象都有一个原型(prototype)属性,它指向另一个对象。当我们访问一个对象的属性时,如果该对象没有该属性,JavaScript会沿着原型链向上查找,直到找到该属性或者到达原型链的顶部(即Object.prototype)。 有多种方式来实现继承

    2024年01月19日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包