彻底弄懂Activity的启动模式和任务栈

3U 与 SV630A 伺服实现 CANLINK 通讯 SD410这组参数特别重要,这个32位特别重要,是防止数值乱码的关键。 阅读详情

Activity的启动模式和任务栈是Android的重点和难点,也是Android面试的常考必考知识点,而很多同学即使时搞Android开发好几年的同学也不一定完全搞懂了,可能也是一知半解。本文让你彻底搞懂Android中Activity的启动模式和任务栈!

前言

一个应用程序当中通常都会包含很多个Activity,每个Activity都是一个具有特定的功能,并且可以让用户进行操作的组件。另外,Activity之间可以相互启动,当前应用的Activity甚至可以去启动其他应用的Activity。

比如你的应用希望去发送一封邮件,你就可以定义一个具有”send”动作的Intent,并且传入一些数据,如对方邮箱地址、邮件内容等。这样,如果另外一个应用程序中的某个Activity声明自己是可以响应这种Intent的,那么这个Activity就会被打开。当邮件发送之后,按下返回键仍然还是会回到你的应用程序当中,这让用户看起来好像刚才那个编写邮件的Activity就是你的应用程序当中的一部分。

所以说,即使有很多个Activity分别都是来自于不同应用程序的,Android系统仍然可以将它们无缝地结合到一起。

那这一切是怎么实现的呢?这就要讲到本文要介绍的Activity任务栈以及Activity启动模式了。

任务栈是什么

任务栈Task,是一种用来放置Activity实例的容器,他是以栈的形式进行盛放,也就是所谓的先进后出,主要有2个基本操作:压栈和出栈,其所存放的Activity是不支持重新排序的,只能根据压栈和出栈操作更改Activity的顺序。

启动一个Application的时候,系统会为它默认创建一个对应的Task,用来放置根Activity。默认启动Activity会放在同一个Task中,新启动的Activity会被压入启动它的那个Activity的栈中,并且显示它。当用户按下回退键时,这个Activity就会被弹出栈,按下Home键回到桌面,再启动另一个应用,这时候之前那个Task就被移到后台,成为后台任务栈,而刚启动的那个Task就被调到前台,成为前台任务栈,Android系统显示的就是前台任务栈中的Top实例Activity。

任务栈的作用

以往基于应用(application)的程序开发中,程序具有明确的边界,一个程序就是一个应用,一个应用为了实现功能可以采用开辟新线程甚至新进程来辅助,但是应用与应用之间不能复用资源和功能。

而Android引入了基于组件开发的软件架构,虽然我们开发android程序,仍然使用一个apk工程一个Application的开发形式,但是对于Aplication的开发就用到了Activity、service等四大组件,其中的每一个组件,都是可以被跨应用复用的,这就是android的神奇之处。

虽然组件可以跨应用被调用,但是一个组件所在的进程必须是在组件所在的Aplication进程中。由于android强化了组件概念,弱化了Aplication的概念,所以在android程序开发中,A应用的A组件想要使用拍照或录像的功能就可以不用去针对Camera类进行开发,直接调用系统自带的摄像头应用(称其B应用)中的组件(称其B组件)就可以了,

但是这就引发了一个新问题,A组件运行在A应用中,B组件运行在B应用中,自然都不在同一个进程中,那么从B组件中返回的时候,如何实现正确返回到A组件呢?Task就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。因为用户所能看到的组件就是Activity,所以Task可以理解为实现一个功能而负责管理所有用到的Activity实例的栈。

栈是一个先进后出的线性表,根据Activity在当前栈结构中的位置,来决定该Activity的状态。正常情况下,当一个Activity启动了另一个Activity的时候,新启动的Activity就会置于任务栈的顶端,并处于活动状态,而启动它的Activity虽然成功身退,但依然保留在任务栈中,处于停止状态,当用户按下返回键或者调用finish()方法时,系统会移除顶部Activity,让后面的Activity恢复活动状态。当然,世界不可能一直这么“和谐”,可以给Activity设置一些“特权”,来打破这种“和谐”的模式,这种特权,就是通过在AndroidManifest文件中的属性andorid:launchMode来设置或者通过Intent的flag来设置的,下面就先介绍下Activity的几种启动模式。

standard

默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。应用场景:绝大多数Activity。


如果以这种方式启动的Activity被跨进程调用,在5.0之前新启动的Activity实例会放入发送Intent的Task的栈的顶部,尽管它们属于不同的程序,这似乎有点费解看起来也不是那么合理,所以在5.0之后,上述情景会创建一个新的Task,新启动的Activity就会放入刚创建的Task中,这样就合理的多了。

singleTop

栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。避免栈顶的activity被重复的创建。应用场景:在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity。当然实际的开发过程中,测试妹纸没准给你提过这样的bug:某个场景下连续快速点击,启动了两个Activity。如果这个时候待启动的Activity使用 singleTop模式也是可以避免这个Bug的。

同standard模式,如果是外部程序启动singleTop的Activity,在Android 5.0之前新创建的Activity会位于调用者的Task中,5.0及以后会放入新的Task中。

singleTask

栈内复用模式, activity只会在任务栈里面存在一个实例。如果要激活的activity,在任务栈里面已经存在,就不会创建新的activity,而是复用这个已经存在的activity,调用 onNewIntent() 方法,并且清空这个activity任务栈上面所有的activity。应用场景:大多数App的主页。对于大部分应用,当我们在主界面点击回退按钮的时候都是退出应用,那么当我们第一次进入主界面之后,主界面位于栈底,以后不管我们打开了多少个Activity,只要我们再次回到主界面,都应该使用将主界面Activity上所有的Activity移除的方式来让主界面Activity处于栈顶,而不是往栈顶新加一个主界面Activity的实例,通过这种方式能够保证退出应用时所有的Activity都能报销毁。

在跨应用Intent传递时,如果系统中不存在singleTask Activity的实例,那么将创建一个新的Task,然后创建SingleTask Activity的实例,将其放入新的Task中。

  1. 假如目前有个任务栈T1中的情况是ABC,这个时候ActivityD以singleTask模式请求启动,其所需要的任务栈正是T1,则系统会直接创建D的实例并将其入栈到T1中。

  2. 假如DActivity启动所需要的任务栈为T2,由于T2和D的实例均不存在,那么系统会先创建任务栈T2,然后再创建D的实例并将其入栈到T2中。我们可以通过设置Activity的taskAffinity属性来模拟这一场景。

<activity android:name=".SingleTastActivtiy" android:label="singleTask launchmode" android:launchMode="signleTask" android:taskAffinity="">

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

  2. 假如目前有两个任务栈,前台任务栈T4的情况为AB,后台任务栈t4里存有CD,假设CD的启动模式均为singleTask,现在由B去启动D,那么整个后台任务都会被切换到前台,这个时候整个栈就变成了ABCD。

  1. 假如上面的其他条件不变,B启动的是C而不是D,那么整个栈的情况就变成了ABC,因为D在C上面,会被清理出栈。

singleInstance

单一实例模式,整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。应用场景:呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。建议谨慎使用。

设置Intent的Flag

系统提供了两种方式来设置一个Activity的启动模式,除了在AndroidManifest文件中设置以外,还可以通过Intent的Flag来设置一个Activity的启动模式,下面我们在简单介绍下一些Flag。

FLAG_ACTIVITY_NEW_TASK

使用一个新的Task来启动一个Activity,但启动的每个Activity都讲在一个新的Task中。该Flag通常使用在从Service中启动Activity的场景,由于Service中并不存在Activity栈,所以使用该Flag来创建一个新的Activity栈,并创建新的Activity实例。

FLAG_ACTIVITY_SINGLE_TOP

使用singletop模式启动一个Activity,与指定android:launchMode=“singleTop”效果相同。

FLAG_ACTIVITY_CLEAR_TOP

使用SingleTask模式来启动一个Activity,与指定android:launchMode=“singleTask”效果相同。

FLAG_ACTIVITY_NO_HISTORY

Activity使用这种模式启动Activity,当该Activity启动其他Activity后,该Activity就消失了,不会保留在Activity栈中。

LaunchMode与StartActivityForResult

我们在开发过程中经常会用到StartActivityForResult方法启动一个Activity,然后在onActivityResult()方法中可以接收到上个页面的回传值,但你有可能遇到过拿不到返回值的情况,那有可能是因为Activity的LaunchMode设置为了singleTask。5.0之后,android的LaunchMode与StartActivityForResult的关系发生了一些改变。两个Activity,A和B,现在由A页面跳转到B页面,看一下LaunchMode与StartActivityForResult之间的关系:


这是为什么呢?

这是因为ActivityStackSupervisor类中的startActivityUncheckedLocked方法在5.0中进行了修改。在5.0之前,当启动一个Activity时,系统将首先检查Activity的launchMode,如果为A页面设置为SingleInstance或者B页面设置为singleTask或者singleInstance,则会在LaunchFlags中加入FLAG_ACTIVITY_NEW_TASK标志,而如果含有FLAG_ACTIVITY_NEW_TASK标志的话,onActivityResult将会立即接收到一个cancle的信息,而5.0之后这个方法做了修改,修改之后即便启动的页面设置launchMode为singleTask或singleInstance,onActivityResult依旧可以正常工作,也就是说无论设置哪种启动方式,StartActivityForResult和onActivityResult()这一组合都是有效的。所以如果你目前正好基于5.0做相关开发,不要忘了向下兼容,这里有个坑请注意避让。

总结

实际开发过程中如果采用比较合理的Activity启动模式来做好任务栈的管理,可以事半功倍。在launchMode的选择上首先要搞清楚当前的Activity的作用,以及实际使用场景来做出合理选择。

飞书日历同步Outlook翻车?我踩过的坑最终用Google Calendar成功的完整配置记录 本文详细记录了从Outlook日历同步到飞书遇到的常见问题及解决方案,特别是通过Google Calendar实现稳定同步的完整配置流程。文章揭示了Outlook同步方案易翻车的原因,并提供了Google Calendar的避坑指南、高级技巧企业级部署建议,帮助用户高效实现日历同步。 阅读详情

相关推荐

Android Studio中的Activity启动模式任务栈

本文聚焦Android开发中Activity的**启动模式(Launch Mode)四种启动模式(standard、singleTop、singleTask、singleInstance)的底层逻辑任务栈如何管理Activity实例(LIFO原则)不同启动模式的典型应用场景通过代码实战验证启动效果(含adb命令查看任务栈)本文从“奶茶店排队”的生活案例切入,逐步拆解启动模式任务栈的关系,结合代码实战演示效果,最后总结应用场景常见问题。任务栈(Task Stack)

移动开发前沿的博客 1328

activity的切换问题(activity与栈)

一、ActivityTask(栈)的关系   Task就像一个容器,而Activity就相当与填充这个容器的东西,第一个东西(Activity)则会处于最下面,最后添加的东西(Activity)则会在最上面。从Task中取出东西(Activity)是从最顶端取出,也就是说最先取出的是最后添加的东西(Activity),以此类推,最后取出的是第一次添加的Activity,而Activity在Ta

简简单单,平平淡淡 2837

PartName_to_PropertyName.zip_python 二次开发 ansa

将part名称赋给对应的property

Activity堆栈管理

task就好像是能包含很多activity的栈。 默认情况下,一个activity启动另外一个activity,两个activity是放在同一个task栈中的,第二个activity压入第一个 activity所在的task栈。当用户按下返回键,第二个activity从栈中弹出,第一个activity又在当前屏幕显示。这样,从用户角度来看,这两个activity就好像是属于同一个应用程序的,...

余炜的博客 408

Android中Activity四种启动模式taskAffinity属性详解

在android应用开发中,打造良好的用户体验是非常重要的。而在用户体验中,界面的引导跳转是值得深入研究的重要内容。在开发中,与界面跳转联系比较紧密的概念是Task(任务)Back Stack(回退栈)。activity启动模式会影响TaskBack Stack的状态,进而影响用户体验。除了启动模式之外,Intent类中定义的一些标志(以FLAG_ACTIVITY_开头)也会影响Task

昨夜星辰的博客 11万+

Activity启动模式SingleTaskIntent.FLAG_ACTIVITY_CLEAR_TOP区别

Activity启动模式 介绍 Android 启动模式之前,先介绍两个概念tasktaskAffinity task:翻译过来就是“任务”,是一组相互有关联的 activity 集合,可以理解为 Activity 是在 task 里面活动的。 task 存在于一个称为 back stack 的数据结构中,也就是说, task 是以栈的形式去管理 activity 的,所以也叫可以称为“...

XG1057415595的博客 7410

Android将后台应用唤起到前台的方法

在我们开发的过程中,经常遇到app进入后台,或者切换到前台的情况。 比如: 从后台切换到前台显示全屏广告实践 来电显示从后台切换到前台 如图显示: 实现主要分为两个步骤: 第一步通过ActivityLifecycleCallbacks判断是否在前后台显示 private void registerActivityLifecycleCallbacks() { registerActiv...

jhonjson的博客 1万+

一文让你彻底弄懂Activity启动模式任务栈

热文导读 | 点击标题阅读如何在2018年变成一个牛B的程序员?吊炸天!74款APP完整源码!2018年快来了,BAT等一二线互联网公司Android面试题汇总作者:尹star博客:https://www.jianshu.com/p/2a9fcf3c11e4Activity启动模式任务栈是Android的重点难点,也是Android面试的常考必考知识点,而很多同学即使搞Android开发好

Java和Android架构 4003

activity启动模式

standard:默认每次激活一个那么任务栈就放置一个新的Activity实例。默认是标准模式。 singleTop:栈顶只能保证有一个该Activity的实例。 singleTask:在当前任务栈中只能有一个实例,如果添加之前任务栈中已经有了该实例,那么已有的该实例以上的实例全部出栈,显示当前的实例。 singleTop:保证多个任务栈中只能有一个实例。 使用场景: standard 

u012175277的博客 327

彻底弄懂Activity四大启动模式

最近有几位朋友给我留言,让我谈一下对Activity启动模式的理解。我觉得对某个知识点的理解必须要动手操作才能印象深刻,所以今天写一篇博文,结合案例理解Activity启动模式。由于之前看过“区长”的一篇博文(文章结尾处有链接)深受启发,因此本文是在那篇文章的基础上更加全面的讲解。        众所周知当我们多次启动同一个Activity,系统会创建多个实例,并把它们按照先进后出的原则一一放入

Android研发专栏 10万+

Activity 启动模式任务栈管理

android任务栈描述,简述四种启动模式包括standard、singleTop、singleTask、singleInstance,并用实例说明他们之间的区别。

程序员闲谈 1万+

【Android】【TaskStack】任务栈Activity启动模式全解析

说到Activity启动模式,相信大家肯定都不模式,多少会有所接触 大多人应该都知道SingleInstance模式可以保证Activity单例,对其它模式的功能具体使用场景应该都不是很清楚 LaunchMode的背后,其实本质上是TaskStack管理,Activity切换管理 这里就给大家完整地讲解下关于任务栈的全部知识原理,以及应用场景 什么是任务栈 顾名思义,任务栈就是通过一个栈的数据结构来管理一系列任务,实际上,这里的任务指的就是Activity任务栈就是管理Activity切换的 任务栈

天天向上 Up Up Up (*^▽^*) 4912

Activity启动模式任务栈以及taskAffinity属性

什么是任务栈一个application在启动的候,能有很多个activity,我们在按下back键的候,会回退到上一个activity,那么系统是如何来管理这些activity呢?答案是以栈(task)的形式,遵循先进后出的原则,默认情况下,一个app只有一个任务栈(task),如果需要,我们可以指定多个任务栈(task)。我们可以总结出以下几点:1.任务栈是app管理activity的一种容器

qq_24295537的博客 1577

精讲任务栈Activity启动模式

任务栈 栈root,栈顶。设备主屏幕是大多数任务的起点。当用户触摸应用启动器中的图标(或主屏幕上的快捷方式),该应用的任务将出现在前台。如果应用不存在任务(应用最近未曾使用),则会创建...

Android技术之家 1321

Android任务栈启动模式

无论开启多少个Activity,最后开启的Activity的实例都会被压入栈的顶端,而之前开启的Activity仍然保存在栈中,但活动已经停止,系统会保存Activety被停止的状态。通常Andaid应用程序都有一个任务栈,每打开一个Activity,该Activity就会被压入任务栈。每销毁一个Activity,该Activity就会被弹出任务栈。如果想要某个Activity在整个应用程序中只有一个实例,则需使用singleTask模式该模式会判断栈中是否存在要启动的Activity,如果存在则。

m0_57150356的博客 408

【转】实现Activity不压入Activity

我们要实现在Activity栈里只存在一个相同的Activity。   例如:A 打开 B, B 打开 C, C 又打开 B, 然后返回i是 B -&gt; C -&gt; A。   如何实现呢?很简单,看代码。 Intent intent = new Intent(this, SearchResult.class); intent.setFlags(Intent.FLAG_AC...

硬币的博客 542

Activity任务栈启动模式详解

1.任务栈简介 1). android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。 2). 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决

jxf_access的专栏 1187

Android应用从后台切换到前台因为数据被GC报异常

问题情景:     我们的应用在前台运行,无论怎么测试,我们的应用都是正常没问题的,这按下home键,手机回到桌面,我们的应用进入后台,过了一段间,我们把应用从后台切换回前台,这测试发现应用崩溃,出现了异常,异常信息里说某一个变量或者某一个对象为NULL,这是因为变量或者对象被系统内存回收机制GC掉了。这个问题自己测试的候很难被发现,如果手机的内存不紧张的话,一般不会遇到这个问题,

zhuawalibai的博客 3236

android程序按home切换到后台,点击launcher的图标切换到前台,当前页面退出回到启动页

问题: 在一次app测试中,偶然发现打开项目按下home键,回到桌面,再次点击app图标,进入app,切换之前的页面突然退出,回到了首页,开始以为是该页面出现bug崩溃了,查看日志,并未发现错误日志,于是在页面的生命周期方法中,写上log,再次重复了上述操作,进入app后,页面一样的退出,查看log,当前页执行Resume()方法后,再次执行了Destroyed()方法,切换了其他页面,...

zuo_er_lyf的博客 7389
上一篇: Android多线程的四种方式
下一篇: Docker 学习笔记
yh_coco
博客等级 码龄14年 3粉丝 11原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值