Android Activity启动模式全面解析

在android里,有4种activity的启动模式,分别为:

“standard” (默认)

“singleTop”

“singleTask”

“singleInstance”

在Android应用中, Activity是最核心的组件, 如何生成一个Activity实例, 可以选择不同的启动模式, 即LaunchMode. 启动模式主要包括: standard, singleTop, singleTask, singleInstance.

标准模式在每次启动时, 都会创建实例; 三种单例模式, 会根据情况选择创建还是复用实例. 在Activity启动中, 创建实例的生命周期: onCreate -> onStart -> onResume; 重用实例的生命周期: onNewIntent -> onResume.

在AndroidManifest的Activity中, 使用launchMode属性, 可以设置启动模式, 默认是standard模式; 使用taskAffinity属性, 并添加包名, 可以设置Activity栈, 默认是当前包名, 只能应用于single模式.

希望通过本文, 可以更好的理解Activity的启动模式(LaunchMode).

全面解析Activity启动模式(LaunchMode)

观察Activity栈的脚本, 参考第5点 .

adb shell dumpsys activity | sed -n -e '/Stack #/p' -e '/Running activities/,/Run #0/p'

1. Standard

标准模式, 启动Activity的默认模式, 被启动的Activity 会运行于 启动的Activity 栈, 因此必须使用Activity的Context启动, 不能使用Application, 否则会报错.

如MainActivity启动TestAActivity.

Stack #1:

Running activities (most recent first):
TaskRecord{3caa65e3 #2711 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
Run #1: ActivityRecord{36b06e99 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2711}
Run #0: ActivityRecord{27396226 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2711}
Stack #0:
Running activities (most recent first):
TaskRecord{27d796c9 #2695 A=com.miui.home U=0 sz=1}
Run #0: ActivityRecord{2e5712cb u0 com.miui.home/.launcher.Launcher t2695}

栈内由下到上: MainActivity -> TestAActivity.

2. SingleTop

栈顶复用模式. 只有Activity位于栈顶, 重复启动时, 会使用默认实例, 即单例模式; 如果位于栈内, 则仍然会创建实例.

MainActivity启动TestA, TestA启动TestB, TestB启动自身, TestB是单例. 观察栈内情况, TestB只有一份实例, 第二次创建复用.

Stack #1:

Running activities (most recent first):
TaskRecord{12abf566 #2712 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=3}
Run #2: ActivityRecord{187d7ff7 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2712}
Run #1: ActivityRecord{a551034 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2712}
Run #0: ActivityRecord{22f9cce4 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2712}

栈内: MainActivity -> TestAActivity -> TestBActivity

MainActivity启动TestA, TestA启动TestB, TestB启动TestC, TestC启动TestB, TestB是单例. 观察栈内情况, 由于TestC是栈顶, TestC启动TestB, TestB不是栈顶, 重新创建TestB实例, 则保留两份TestB.

Stack #1:

Running activities (most recent first):
TaskRecord{1792f5f0 #2715 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=5}
Run #4: ActivityRecord{1e70110b u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2715}
Run #3: ActivityRecord{c7f4dce u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivity t2715}
Run #2: ActivityRecord{254536cd u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2715}
Run #1: ActivityRecord{36b2da15 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2715}
Run #0: ActivityRecord{3a1c4a6a u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2715}

栈内: MainActivity -> TestAActivity -> TestBActivity ->TestCActivity -> TestBActivity

3. SingleTask

栈内复用模式, 只要Activity在一个栈中存在, 多次调用时, 都不会创建实例, 即单例模式.

情况包含以下几种:

(1) 任务栈不存在, 初次启动SingleTask实例, 会创建任务栈和实例.

MainActivity启动TestA, TestA启动TestB, TestB是SingleTask, 并且任务栈不同. 观察可知, 系统包含两个任务栈, TestB位于其他任务栈中.

Stack #1:

Running activities (most recent first):
TaskRecord{d5d53d4 #2727 A=me.chunyu.spike.stack U=0 sz=1}
Run #2: ActivityRecord{1d720e55 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2727}
TaskRecord{a3f797d #2726 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
Run #1: ActivityRecord{ffd689d u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2726}
Run #0: ActivityRecord{192310ac u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2726}

使用taskAffinity属性, 添加新的Activity栈, 与SingleTask配合使用, Standard模式无效.

新任务栈是 me.chunyu.spike.stack .

(2) 任务栈存在, 初次启动SingleTask实例, 会直接入栈, 与Standard模式相同.

(3) 任务栈相同, 再次启动SingleTask实例, 实例会置于栈顶, 并清除其上面实例, 具有clearTop的效果.

MainActivity启动TestA, TestA启动TestB, TestB是SingleTask, TestB启动TestC, TestC重新启动TestB, 则TestC会出栈. 观察可知, TestC出栈, TestB位于栈顶.

Stack #1:

Running activities (most recent first):
TaskRecord{18230815 #2737 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=3}
Run #4: ActivityRecord{1126c300 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2737}
Run #3: ActivityRecord{3114fee8 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2737}
Run #2: ActivityRecord{f8e235d u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2737}

TestC启动TestB, SingleTask模式, 导致clearTop, TestC出栈.

(4) 任务栈不同, 再次启动SingleTask实例, 会导致任务栈切换, 后台置于前台.

这比较难理解.MainActivity启动TestA, TestA启动TestB(SingleTask实例, 不同任务栈), TestB启动TestC(与B类似), 则MainActivity和TestA相同栈, TestB和TestC相同栈, 此时栈顶是TestC. 按Home键, 再次启动应用, 则默认任务栈会启动, TestA启动, TestA启动TestC. 应用当前状态如下.

Stack #1:

Running activities (most recent first):
TaskRecord{1d05e6c9 #2754 A=me.chunyu.spike.stack U=0 sz=2}
Run #4: ActivityRecord{3f77e822 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivity t2754}
TaskRecord{3fe736d0 #2753 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
Run #3: ActivityRecord{15f0470e u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2753}
TaskRecord{1d05e6c9 #2754 A=me.chunyu.spike.stack U=0 sz=2}
Run #2: ActivityRecord{181229e6 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2754}
TaskRecord{3fe736d0 #2753 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
Run #1: ActivityRecord{28628d61 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2753}
TaskRecord{2d646058 #2719 A=com.android.incallui U=0 sz=1}

TestC至于栈顶, 点击Back键, 不是返回TestA(启动TestC的实例), 而是TestB, 即优先返回相同栈的实例. 再次是TestA, 然后是MainActivity, 依次出栈.

4. SingleInstance

单实例模式, 启动时, 系统会为其创造一个单独的任务栈, 以后每次使用, 都会使用这个单例, 直到其被销毁, 属于真正的单例模式.

示例: MainActivity启动TestA, TestA启动TestB(SingleInstance模式),

TestB启动TestC, TestC再启动TestB, 则仍启动上一次的TestB,

TestC合并入默认栈(MainActivity+TestA).

Stack #1:

Running activities (most recent first):
TaskRecord{384e3928 #2765 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=1}
Run #3: ActivityRecord{1ffc5b6b u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2765}
TaskRecord{2ad03544 #2764 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=3}
Run #2: ActivityRecord{293d8c37 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivity t2764}
Run #1: ActivityRecord{158bc0f3 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2764}
Run #0: ActivityRecord{77691cf u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2764}

5. startActivityForResult

Thx@回调的幸福时光

startActivityForResult不同于startActivity, 使用LaunchMode模式启动Activity时, 也会有一些不同, 可以正常传递数据, 但是无法连续创建自己时, 会生成多份实例.

TestB(singleTask模式)使用startActivity创建自己时, 会使用默认实例, 即单例; 而使用startActivityForResult创建自己时, 会生成一份新的示例.

Stack #1:

Running activities (most recent first):
TaskRecord{323200ac #2786 A=me.chunyu.clwang.stack U=0 sz=3}
Run #4: ActivityRecord{3f9e14f3 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2786}
Run #3: ActivityRecord{30d8f17b u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2786}
Run #2: ActivityRecord{11b95b5c u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivity t2786}
TaskRecord{c86e175 #2785 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
Run #1: ActivityRecord{3558d7c4 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2785}
Run #0: ActivityRecord{1b8620c u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2785}

由此可知, 因为startActivityForResult需要返回值, 会保留实例, 覆盖单例效果.

注意: 4.x版本通过startActivityForResult启动singleTask, 无法正常获取返回值, 参考 .

5.x以上版本修复此问题, 考虑兼容性, 不推荐使用startActivityForResult和singleTask.

启动模式做为Activity的重要属性, 还是需要比较透彻的掌握.

(0)

相关推荐

  • Android中通知栏跳动问题解决方法

    曾经遇到过这样的问题,在我的代码中使用了通知栏,一切都正常,但是就是正在进行的通知栏中属于我的程序的那一条总是上下跳来跳去,一闪一闪的.感觉用户体验很不好,于是Google一下,找到了解决方法. 在我的代码,我是这样写的. 复制代码 代码如下: notification.when = System.currentTimeMillis(); 这就是问题的关键,对于通知来说,when这个属性值应该在activity一启动的时候就应该固定.如果没有固定,就会使用默认的值,默认的值就是当前的时间,即Sy

  • Android消息通知栏的实现方法介绍

    背景知识:可以用Activity和Service来开始消息通知,两者的区别在于一个是在前台触发,一个是后台服务触发.要使用消息通知,必须要用到两个类:NotificationManager和Notification,其他NotificationManager的初始化是用getSystemService方法,并且通过notify方法来向android系统发送消息栏通知和显示.效果 :代码: 复制代码 代码如下: //消息通知栏        //定义NotificationManager     

  • Android利用Intent启动和关闭Activity

    一.简介 Android应用程序中一般都有多个Activity,在Activity中,通过调用StartActivity方法,并在该方法的参数中传递Intent对象,就可以实现不同Activity之间的切换和数据传递. 通过StartActivity方法传递intent对象来启动另一个Activity时,可分为两类: l 显式启动:在创建的Intent对象中明确指定启动的是哪个Activity: l 隐式启动:安卓系统根据Intent的动作和数据决定应该启动哪个Activity. 1.显式启动A

  • Android Activity启动模式之standard实例详解

    本文实例讲述了Android Activity启动模式之standard.分享给大家供大家参考,具体如下: Android的活动是通过任务Task来进行管理的,一个任务就是一组放在栈里的活动的集合,即所谓的返回栈(Back Stack).栈具有先进后出.后进先出的特性.当启动一个活动时,活动会在返回栈中入栈,处于栈顶位置,当按下返回键或者调用finish方法会销毁一个活动,此时栈顶活动会出栈,届时又会有新的活动处于栈顶位置. 在Android中,活动的启动模式有四种,根据不同的需求可以为活动设置

  • 关于Android中点击通知栏的通知启动Activity问题解决

    前言 最近遇到一个很奇葩的问题,终于解决了,所以想着记录一下,方便大家或者自己以后有需要的时候可以参考学习. 问题场景 用小米手机使用小米推送一条消息,然后点击通知栏中的消息启动应用,然后进入会话的Activity.应用启动后,如果当前界面不是会话界面,那么新消息会在通知栏显示消息提醒,然后点击会话消息后却进不了会话的Activity,即点击了通知栏通知后,系统都没有启动指定Activity的意思,没有看到系统启动Activity的Log,到是会看到系统处理这个Activity的影子. 这个指定

  • 简单介绍Android中Activity的四种启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. Activity有四种启动模式: 1. standard,默认的启动模式,只要激活Activity,就会创建一个新的实例,并放入任务栈中,这样任务栈中可能同时有一个Activity的多个实例. 2. singleTop,激活Activity时,如果栈顶是这个Activity,就不会创建新的实例:如果栈顶

  • Android实现通知栏透明的方法

    这个特性是andorid4.4支持的,最少要api19才可以使用,也就是说如果Android的机子是低于4.4,沉浸通知栏是没有效果的.下面介绍一下使用的方法,非常得简单. /** * 设置通知栏 这个方法在onCreate()实现,如果是在父类的onCreate()中添加,即使所有继承了该父类都会有沉浸通知栏. */ public void initSystemBar() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

  • Android中Activity生命周期和启动模式详解

    Activity生命周期经典图解: 按键对生命周期的影响: BACK键: 当我们按BACK键时,我们这个应用程序将结束,这时候我们将先后调用onPause()->onStop()->onDestory()三个方法. 再次启动App时,会执行onCreate()->onStart()->onResume() HOME键: 当我们打开应用程序时,比如浏览器,我正在浏览NBA新闻,看到一半时,我突然想听歌,这时候我们会选择按HOME键,然后去打开音乐应用程序,而当我们按HOME的时候,A

  • Android Activity启动模式全面解析

    在android里,有4种activity的启动模式,分别为: "standard" (默认) "singleTop" "singleTask" "singleInstance" 在Android应用中, Activity是最核心的组件, 如何生成一个Activity实例, 可以选择不同的启动模式, 即LaunchMode. 启动模式主要包括: standard, singleTop, singleTask, singleIn

  • Android Activity启动模式之singleTask实例详解

    本文实例分析了Android Activity启动模式之singleTask.分享给大家供大家参考,具体如下: 前面的文章介绍了Android 活动Activity的启动模式:standard 和singleTop .本文继续介绍Activity的下一个启动模式:singleTask. singleTask:当设置活动的启动模式为singleTask时,首先检查返回栈中是否存在当前活动,如果存在当前活动的实例,则直接使用当前实例,并把当前活动之上的所有活动pop出栈,即当前活动位于栈顶位置. 代

  • Android Activity启动模式之singleTop实例详解

    本文实例讲述了Android Activity启动模式之singleTop.分享给大家供大家参考,具体如下: 在前面文章<Android Activity启动模式之standard实例详解>中,我们介绍了活动的默认启动模式standard,本文继续介绍Activity的singleTop模式. singleTop模式:当Activity的活动模式设置为singleTop时,在启动活动时首先检查栈顶活动是否是该活动,如果是,在使用当前实例,否则继续创建新的实例. (1)修改AndroidMani

  • 浅析Activity启动模式

    前言 平常我们启动活动的时候就是直接startActivity或许并没有注意活动的启动模式,默认情况下都是以默认的启动模式启动.但启动模式有时候是比较重要的.例如一个活动你想他只启动一次不要有多个实例,那么你可能需要把他设置为singleTask模式.所以有必要了解一下这一些启动模式.同时要注意一下,启动模式≠启动方式,启动方式是指显示启动和隐式启动,不要混淆,显示启动和隐式启动后续我会有专门的文章讲解. 关于任务栈简介 要了解启动模式,首先要了解一下关于任务栈的概念.关于任务栈的实现原理等我在

  • Android 10 启动Init进程解析

    目录 按下电源键时,android做了啥? init进程解析 FirstStageMain SetupSelinux SecondStageMain init.rc 解析 按下电源键时,android做了啥? 当我们按下电源键时,手机开始上电,并从地址0x00000000处开始执行,而这个地址通常是Bootloader程序的首地址. bootloader是一段裸机程序,是直接与硬件打交道的,其最终目的是“初始化并检测硬件设备,准备好软件环境,最后调用操作系统内核”.除此之外,bootloader

  • Android Activity启动流程刨析

    目录 前言 一.Binder的基本理解 二.Activity启动的双向IPC过程 三.AMS服务注册 前言 上篇文章写到 Service 的启动过程: 相对来说Activity的启动过程比Service的启动过程更为复杂,其一Activity的生命周期方法比Service多,其二Activity具有启动模式和返回栈: 写本文的目的在于更清晰的梳理Activity的启动过程,加强自己的内功修炼,力在以最简单的方式让大家理解,跟大家一起学习 一.Binder的基本理解 Activity的启动有多次I

  • 通过实例解析android Activity启动过程

    注:只是说明启动activity的过程(ActivityThread如何与ActivityManagerService简称AmS进行进程间通信调用全过程),不解析android从zygote(受精卵)到整个系统服务的启动 具体来讲,启动activity的方式有以下几种: 在应用程序中startActivity()或startActivityForResult()方法启动指定activity 在HOME(桌面)程序中单击应用图标,启动新的activity 按"BACK"键结束当前acti

  • Android Activity的生命周期与启动模式全面解读

    目录 Activity概述 Activity生命周期 生命周期的调用顺序 演示 Activity的启动模式 启动模式的设置 standard(默认standard) singleTop singleTask singleInstance Activity概述 • Activity(活动)是Android应用程序中最基本的组成单位. • Activity主要负责创建显示窗口,一个Activity对象通常就代表了一个单独的屏幕. • Activity是用户唯一可以看得到的组件,用来与用户进行交互的.

  • Android入门之Activity四种启动模式(standard、singleTop、singleTask、singleInstance)

    当应用运行起来后就会开启一条线程,线程中会运行一个任务栈,当Activity实例创建后就会放入任务栈中.Activity启动模式的设置在AndroidManifest.xml文件中,通过配置Activity的属性android:launchMode=""设置. 一.启动模式介绍 启动模式简单地说就是Activity启动时的策略,在AndroidManifest.xml中的标签的android:launchMode属性设置: 启动模式有4种,分别为standard.singleTop.s

随机推荐