我们知道,Android有四种启动模式,分别是stander、singleTop、singleTask、singleInstance。
设置Activity的启动模式很简单,只要在AndroidManifest里面设置就可以。

四种模式的出现是为了解决各种应用场景,下面我们来分析一下各种应用场景,以及其内部任务栈发生了什么样的变化。
首先我们来了解一下什么是栈,什么是任务栈。栈是一种后进先出的数据结构,有两种操作,push和pop,你可以把它想象成是在盒子里装衣服,拿衣服时最上面那件是最先拿出来的,最底下那件肯定是最后才拿出来的。而在Android里的Activity就是以这样的栈结构来进行管理的,我们称之为任务栈。我们可以通过adb shell sysdump命令来查看当前设备的任务栈(需要配置环境变量)。输入我们可以看到:

TaskRecord{7f67d30 #10439 A=com.wison.demo U=0 sz=2}
Run #3: ActivityRecord{813695e u0 com.wison.demo/.activity.MainActivity t10439}

这里可以知道当前栈栈名为com.wison.demo,该栈有一个Activity,名字是MainActivity。

四种模式都跟任务栈有关联,我们一个个来讲。

stander
经典模式,也是默认的一个启动模式,在Android中我们用普通的方式启动一个Activity,就是这种模式。在这种模式下,每次启动一个Activity,都会将创建一个新的实例并放入启动这个Activity的任务栈中。

TaskRecord{7f67d30 #10439 A=com.wison.demo U=0 sz=2}
Run #5: ActivityRecord
{c513ekd u0 com.wison.demo/.activity.AActivity t10439}
Run #4: ActivityRecord
{d2164bd u0 com.wison.demo/.activity.AActivity t10439}
Run #3: ActivityRecord
{813695e u0 com.wison.demo/.activity.MainActivity t10439}

可以看到,MainActivity启动了AActivity并放入它所在的任务栈当中,而AActivity在启动一个AActivity会重新创建并放入该栈中。
而当我们尝试用Application去启动Activity时会发现报出以下错误

如刚才所说,每次启动一个Activity,都会将创建一个新的实例并放入启动这个Activity的任务栈中。而非Activity类型的Context没有任务栈一说,因此会报错。解决方法是启动的时候为其加上一个FLAG_ACTIVITY_NEW_TASK的标志,该标志会为该启动的Activity创建一个新的任务栈并将其放入其中。

singleTop
栈顶复用模式,当Activity设置这个模式后,每次启动这个Activity系统都会判断该Activity是否在栈顶存在,如果存在则不创建,如果不在栈顶则创建一个新的实例。
假设当前任务栈有ABC三个Activity,如果C的启动模式为singleTop,则当C启动C时,由于在栈顶C已经存在,这时候不会创建一个新的C实例,而是会复用栈顶的C。即任务栈还是ABC,这时候会调用C的onNewIntent,打Log我们可以看到

com.wison.demo I/tag: onPause
com.wison.demo I/tag: onNewIntent
com.wison.demo I/tag: onResume

singleTask
栈内复用模式,在该模式下,只要该Activity在任何一个栈内存在,就不会创建新的实例,同样的,会调用它的onNewIntent。如果这时该Activity不在栈顶,则将其之上的Activity全部弹出栈外,并将该Activity置于栈顶。
这里分几种情况分析。
一、
任务栈内有AB两个Activity,C的启动模式为singleTask,则启动C后的栈内情况如下

TaskRecord{7f67d30 #10439 A=com.wison.demo U=0 sz=2}
Run #5: ActivityRecord
{c513ekd u0 com.wison.demo/.activity.CActivity t10439}
Run #4: ActivityRecord
{d2164bd u0 com.wison.demo/.activity.BActivity t10439}
Run #3: ActivityRecord
{813695e u0 com.wison.demo/.activity.AActivity  t10439}

当C再启动C时,由于C存在于栈顶,因此C会调用

com.wison.demo I/tag: onPause
com.wison.demo I/tag: onNewIntent
com.wison.demo I/tag: onResume

二、
任务栈内有ABCD,C的启动模式为singleTask,这时候D再启动C,任务栈的情况为

TaskRecord{7f67d30 #10439 A=com.wison.demo U=0 sz=2}
Run #5: ActivityRecord
{c513ekd u0 com.wison.demo/.activity.CActivity t10439}
Run #4: ActivityRecord
{d2164bd u0 com.wison.demo/.activity.BActivity t10439}
Run #3: ActivityRecord
{813695e u0 com.wison.demo/.activity.AActivity  t10439}

从任务栈我们可以看到D已经不在任务栈,我们再看看Log的情况

com.wison.demo I/DActivity: onPause
com.wison.demo I/CActivity: onNewIntent
com.wison.demo I/CActivity: onStart
com.wison.demo I/CActivity: onResume
com.wison.demo I/DActivity: onStop
com.wison.demo I/DActivity: onDestroy

可以看出,D已经执行onDestroy了。这也印证了如果这时该Activity不在栈顶,则将其之上的Activity全部弹出栈外,并将该Activity置于栈顶。

三、
这里我们介绍一个新的概念,TaskAffinity,该属性能够Activity所需的任务栈名,默认为包名。我们可以在清单中进行设置,如图

这里我们设置CActivity的TaskAffinity为com.wison.test,接着我们按顺序启动ABC,再来看看任务栈的情况

 TaskRecord{b8815da #10599 A=com.wison.test U=0 sz=1}Run #4: ActivityRecord{988e526 u0 com.wison.demo/.activity.CActivity t10599}TaskRecord{35ea0b #10597 A=com.wison.demo U=0 sz=2}Run #3: ActivityRecord{7efda4e u0 com.wison.demo/.activity.BActivity t10597}Run #2: ActivityRecord{9dbb6a1 u0 com.wison.demo/.activity.AActivity t10597}

可以看到,CActivity是运行在com.wison.test这个任务栈里的,这时候C是在前台的,所以com.wison.test叫做前台任务栈,而com.wison.demo则叫做后台任务栈。

singleInstance
这个模式可以称为singleTask的加强版,我们可以称它为单例模式,在这个模式中,如果在任何一个任务栈中没有该实例,则单独创建一个任务栈并放入该实例,如果在某个任务栈中有该实例,则将该实例任务栈调到前台任务栈来。
设置CActivity的LaunchMode为singleInstance,再来启动ABC,我们看看任务栈的情况。

TaskRecord{1ed9db9 #10604 A=com.wison.demo U=0 sz=1}
Run #4: ActivityRecord{4c9334b u0 com.wison.demo/.activity.CActivity t10604}TaskRecord{72d87ac #10603 A=com.wison.demo U=0 sz=2}
Run #3: ActivityRecord{f28fcd3 u0 com.wison.demo/.activity.BActivity t10603}
Run #2: ActivityRecord{3fc4983 u0 com.wison.demo/.activity.AActivity t10603}

可以看到虽然没有指定TaskAffinity,但是CActivity还是单独在一个任务栈里。看看任务栈的情况。

TaskRecord{1ed9db9 #10604 A=com.wison.demo U=0 sz=1}
Run #4: ActivityRecord{4c9334b u0 com.wison.demo/.activity.CActivity t10604}TaskRecord{72d87ac #10603 A=com.wison.demo U=0 sz=2}
Run #3: ActivityRecord{f28fcd3 u0 com.wison.demo/.activity.BActivity t10603}
Run #2: ActivityRecord{3fc4983 u0 com.wison.demo/.activity.AActivity t10603}

可以看到虽然没有指定TaskAffinity,但是CActivity还是单独在一个任务栈里。我们接着尝试在C中启动D,看看会是什么情况。

TaskRecord{891d010 #10794 A=com.wison.demo U=0 sz=2}
Run #3: ActivityRecord{cf7d657 u0 com.wison.demo/.activity.DActivity t10794}TaskRecord{367ec1a #10795 A=com.wison.demo U=0 sz=1}
Run #2: ActivityRecord{12cbb50 u0 com.wison.demo/.activity.CActivity t10795}TaskRecord{891d010 #10794 A=com.wison.demo U=0 sz=2}
Run #1: ActivityRecord{3738523 u0 com.wison.demo/.activity.BActivity t10794}
Run #0: ActivityRecord{6bf361b u0 com.wison.demo/.activity.AActivity t10794}

我们可以看到,ABD在一个任务栈,而C则还是单独在一个任务栈里,而当我们从D再次启动C时,会出现跟singleTask一样的情况。

com.wison.demo I/DActivity: onPause
com.wison.demo I/CActivity: onNewIntent
com.wison.demo I/CActivity: onStart
com.wison.demo I/CActivity: onResume
com.wison.demo I/DActivity: onStop
com.wison.demo I/DActivity: onDestroy

而C的任务栈当然也被放置到前台。

Android启动模式分析相关推荐

  1. Android:四种启动模式分析

    2019独角兽企业重金招聘Python工程师标准>>> 在一个项目中会包括着多个Activity,系统中使用任务栈来存储创建的Activity实例,任务栈是一种"后进先出& ...

  2. React Native Android启动白屏的一种解决方案下

    React Native Android启动白屏的一种解决方案下 参考文章: (1)React Native Android启动白屏的一种解决方案下 (2)https://www.cnblogs.co ...

  3. React Native Android启动白屏的一种解决方案上

    React Native Android启动白屏的一种解决方案上 参考文章: (1)React Native Android启动白屏的一种解决方案上 (2)https://www.cnblogs.co ...

  4. android布局优化方案,Android启动优化-布局优化

    Android启动优化-布局优化 安卓应用开发发展到今天,已经成为一个非常成熟的技术方向,从目前的情况看,安卓开发还是一个热火朝天的发展,但高级人才却相对较少,如今移动互联网的开发者也逐渐开始注重插入 ...

  5. android130 android启动

    Android的编译环境只支持Linux和Mac OS,google推荐使用64位操作系统,### android启动> #### 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有 ...

  6. Android启动过程深入解析【转】

    转自:http://www.open-open.com/lib/view/open1403250347934.html 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么 ...

  7. Android启动界面优化技巧-Splash Screens的正确方式

    备注:这里是开发跨平台App时,适配Android启动屏幕,主要为了防止白屏.玩Android开源App 往往我们在开发Android的时候会出现白屏等等,主要原因就是启动时需要加载的资源过多,从而影 ...

  8. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )

    文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...

  9. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )

    文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...

  10. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )

    文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...

最新文章

  1. html动画效果开源代码,8款强大的CSS3/HTML5动画及应用源码
  2. 如何将模糊的图片变得清晰
  3. linux 设置登录失败n次 锁定账户 /etc/pam.d/system-auth
  4. Ubuntu nginx 配置实例
  5. (诊断)No module named MySQLdb
  6. (转)在Total Commander下使用SVN
  7. 使用sklearn进行数据预处理 —— 归一化/标准化/正则化
  8. 404 单页应用 报错 路由_通过 Laravel 创建一个 Vue 单页面应用(五)
  9. Python以进程方式无黑窗在后台运行(无命令窗)
  10. Spring Boot 核心原理与源码解析-大纲
  11. Ext2 常见界面界面(grid分页、窗口布局、下拉框级联)
  12. (5) IFC 总体架构 (Industry Foundation Class)
  13. 关于一些桌面、移动应用开发的平台
  14. WPF开发实例——仿QQ登录界面
  15. pro-engineerUG
  16. Excel小问题 - 前三个非空单元格数值之和
  17. 小技巧:两种方式快速实现平滑涂鸦画板
  18. kylin2.1.0 + CHD5.7环境搭建
  19. python面板数据分析代码_面板数据分析是什么如何进行面板数据分析?
  20. MATLAB 错误使用 instfreq TFD 应“非负”

热门文章

  1. 计算两个日期之间,相差多少天C语言详解
  2. IDEA中添加翻译插件
  3. 大学生社会实践报告 模板
  4. ddr读时序波形_DDR3时序测试,信号完整性测试
  5. 探索汽车行业大数据应用
  6. VC、VS、QT界面预览快捷键小记
  7. 美联储加息落地 题材股继续活跃创业板大涨1.85%
  8. 基于氚云平台的应用开发学习(一)
  9. dir_recurse是 php函数,dir_recurse是一个函数么?
  10. C64x EDMA Architecture