Android启动模式分析
我们知道,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启动模式分析相关推荐
- Android:四种启动模式分析
2019独角兽企业重金招聘Python工程师标准>>> 在一个项目中会包括着多个Activity,系统中使用任务栈来存储创建的Activity实例,任务栈是一种"后进先出& ...
- React Native Android启动白屏的一种解决方案下
React Native Android启动白屏的一种解决方案下 参考文章: (1)React Native Android启动白屏的一种解决方案下 (2)https://www.cnblogs.co ...
- React Native Android启动白屏的一种解决方案上
React Native Android启动白屏的一种解决方案上 参考文章: (1)React Native Android启动白屏的一种解决方案上 (2)https://www.cnblogs.co ...
- android布局优化方案,Android启动优化-布局优化
Android启动优化-布局优化 安卓应用开发发展到今天,已经成为一个非常成熟的技术方向,从目前的情况看,安卓开发还是一个热火朝天的发展,但高级人才却相对较少,如今移动互联网的开发者也逐渐开始注重插入 ...
- android130 android启动
Android的编译环境只支持Linux和Mac OS,google推荐使用64位操作系统,### android启动> #### 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有 ...
- Android启动过程深入解析【转】
转自:http://www.open-open.com/lib/view/open1403250347934.html 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么 ...
- Android启动界面优化技巧-Splash Screens的正确方式
备注:这里是开发跨平台App时,适配Android启动屏幕,主要为了防止白屏.玩Android开源App 往往我们在开发Android的时候会出现白屏等等,主要原因就是启动时需要加载的资源过多,从而影 ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )
文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )
文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )
文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...
最新文章
- html动画效果开源代码,8款强大的CSS3/HTML5动画及应用源码
- 如何将模糊的图片变得清晰
- linux 设置登录失败n次 锁定账户 /etc/pam.d/system-auth
- Ubuntu nginx 配置实例
- (诊断)No module named MySQLdb
- (转)在Total Commander下使用SVN
- 使用sklearn进行数据预处理 —— 归一化/标准化/正则化
- 404 单页应用 报错 路由_通过 Laravel 创建一个 Vue 单页面应用(五)
- Python以进程方式无黑窗在后台运行(无命令窗)
- Spring Boot 核心原理与源码解析-大纲
- Ext2 常见界面界面(grid分页、窗口布局、下拉框级联)
- (5) IFC 总体架构 (Industry Foundation Class)
- 关于一些桌面、移动应用开发的平台
- WPF开发实例——仿QQ登录界面
- pro-engineerUG
- Excel小问题 - 前三个非空单元格数值之和
- 小技巧:两种方式快速实现平滑涂鸦画板
- kylin2.1.0 + CHD5.7环境搭建
- python面板数据分析代码_面板数据分析是什么如何进行面板数据分析?
- MATLAB 错误使用 instfreq TFD 应“非负”