IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

启动activity的4种模式(standard、singleTop、singleTask、singleINstance)

Android相关技术 2016-04-02 13:44:45 累计浏览 3,078 次
本机暂存

在AndroidManifest.xml中配置activity时,android:launchMode属性会指定启动activity的模式,有四种:

  1. standard

  2. singleTop

  3. singleTask

  4. singleInstance

这四种模式一般配合Intent属性变量FLAG_ACTIVITY_XXX使用,比如FLAG_ACTIVITY_NEW_TASK,本文暂时撇开FLAG_ACTIVITY_XXX,只讨论这四种模式的启动结果,先考虑只在同一个应用下的情况。

standard模式

系统默认情况下就是standard模式,假如A中设置为默认模式,A中有一个按钮,单击按钮时只启动自己,看看启动后的结果。AndroidManifest.xml、A和源码及布局分别为:

<?xml version="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name="com.example.administrator.myapplication.AActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.feeyan.www.a_activity"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>
    </application>

</manifest>
publicclassAActivityextendsAppCompatActivity{

    @Override
    protectedvoidonCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.a_layout);
    }

    publicvoidstartToB(View view){
        startActivity(newIntent("com.feeyan.www.a_activity"));
    }
}
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.administrator.myapplication.AActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="to B"
        android:id="@+id/button"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:textSize="20sp"
        android:onClick="startToB"/>
</RelativeLayout>

注:本文案例在小米4上测试

假设现在没有运行程序,先通过命令dumpsys activity activities在串口中查看所有activity栈信息:

没有启动案例时的栈

看红色区域,activity栈中只有一个代号为0的栈,栈中也只有一个id号为#1的task和id号为#0的ActivityRecord,ActivityRecord中保存的包名是com.miui.home,启动类名为.launcher.Launcher,也就是说,目前Activity栈中只有Launcher应用,没有别的应用。

现在启动案例,启动后的栈信息:

启动案例后的栈

案例启动后,系统新建了一个栈stack #1,其中有新启动的Activity实例AActivity,保存在id号为#24的task中

然后,点击按钮再次启动AActivity,启动后的栈信息为:

再次启动AActivity后的栈

在同样的stack #1、同样的task #24中多了一个AActicity实例,两个实例对应的ActivityRecord地址不一样,一个是42e23ae0,一个是42da3a08。

默认标准模式,每启动一次,就创建一个新实例,并放到栈顶,并且该实例放在同样的任务task中、同样的activity栈中。不会再新创建栈、task。

singleTop模式

如果把A设为默认Standard标准模式,把B设置singleTop模式,A启动B后看看什么情况,相关源码较简单,不再添加,本文后又源码下载地址。

A启动B后的栈

在stack #1中,新创建了一个task #25,包含B实例和A实例,新启动的实例位于栈顶。如果在B中点击按钮再次启动B,发现栈信息不会改变,而且无论点击多少次按钮,stack #1栈中还是B和A,不会重新创建实例。

假设在A中启动B,B启动C,C设为标准模式,启动后的栈信息:

A启动B,B启动C后的栈

栈顶是C,其次是B和A,A在栈最底部;如果此时在C中点击按钮再启动B呢?启动后的栈信息:

A启动B,B启动C,C再次启动B后的栈

发现栈顶又创建了一个B实例,不会复用栈中已有的实例,栈中总共有2个B实例!

singleTop模式跟标准Standard模式差不多,只不过多了一种情况,分为两种情况来看:

1.  如果栈中已经有了待启动activity实例并且位于栈顶,那么再次启动该activity时,系统会直接复用该实例,不会再创建新的实例;如果没有,就新创建实例,并放到栈顶;

2. 如果栈中已经有了待启动activity实例,但不在栈顶,那么再次启动该activity时,系统会再次创建新的实例并将该实例放到栈顶,这种情况和standard模式一样。

singleTask模式

如果A和C设置standard模式,B设为singleTask模式,A启动B,B启动C,按照这个顺序启动后,栈中自底向上为:A—-B—-C,如果此时在C中点击按钮再次启动B呢?启动后栈信息为:

singleTask模式下A启动B,B启动C,C再次启动B后的栈

此时,Task #30中只有A和B,B位于栈顶,没有C了,这个和singleTop有了明显的差别,在singleTop中C不会消失,而此时C却消失了。

1.  如果栈中已经有了待启动activity实例并且位于栈顶,那么再次启动该activity时,系统会直接复用该实例,不会再创建新的实例;如果没有,就新创建实例,并放到栈顶;

2. 如果栈中已经有了待启动activity实例但不在栈顶,那么再次启动该activity时,系统会复用已有实例,并且把位于该实例之上的所有其他activity实例移出栈,同时将该实例放在栈顶。

singleInstance模式

如果设A和C为standard模式,B为singleInstance模式,A启动B后栈信息为:
singleInstance模式下A启动B后的栈

发现和上面三种情况都不一样的地方,在栈中新创建了一个task,并把B放入其中,上面三种情况都是在同样的task中。如果再B中启动C,启动后的栈:

singleInstance模式下A启动B后,B启动C的栈

A和C都是标准模式,都在同一个task中,而B在另外一个task中,因为启动了C,C在栈顶。如果再C中点击按钮再次启动B,结果会是什么?

singleInstance模式下A启动B后,B启动C,C再启动B的栈

B所在的task跑到了栈顶,A和C所在的task在栈底。而且B始终只有一个实例。

1.  如果栈中没有待启动activity实例,启动该activity时,系统会新创建一个task,再创建一个待启动activity实例,把该实例放到新task中,并且该task会在栈顶;

2. 如果栈中已经有了待启动activity实例,不管在栈的什么位置,系统都会复用已存在实例,并且把该实例放在栈顶,而且该task中只有一个该实例,不会再有第二个实例,也不会有其他activity实例;

3. 如果一个应用中有多个activity都设置成singleInstance模式,那么每个启动后的activity实例都保存在一个task中,不会在同一个task中,task和实例是一对一关系。

同一应用中测试小结

a. standard、singleTop存在多种实例的可能(“可能”二字表明,singleTop情况下,如果栈顶已有实例,再次启动时只会复用,如果不在栈顶,就会新创建实例);而singleTask和singleInstance只有一个实例,再次启动时不会创建新实例;

b. singleTask和singleInstance模式,再次调用时都会先调用onNewIntent方法,再调用onResume方法;对于singleTop,如果栈顶已有实例,也是先调用onNewIntent方法,再调用onResume方法,如果不在栈顶或者还没有实例,就会先调用onCreate方法;

c. singleInstance模式不同于其他三种,首次启动时会新开启一个task,该task只包含一个实例;再次启动时只会复用该task,不再新创建。

同一应用中只有1个app,源码地址:https://yunpan.cn/crybfHCWhcbwW  访问密码:e7cb

不同应用之间测试小结

上面分析了在同一应用中的情况,再看看不同应用之间的情形。通过测试得知:standard、singleTop没有什么改变,还是在在同样的栈、task中;singleInstance模式下也没有改变,还是会创建新的task并保存唯一实例;但singleTask却不一样,首次启动时,系统会在当前栈中创建一个新的task,再次启动时,复用已有task;而在同一应用中,再次启动时,不会再创建新task的,直接复用已有task。

不同应用之间测试有2个app,源码地址:https://yunpan.cn/crKLt2CuZ7drc  访问密码 e4b8

最终总结

不管是同一应用中还是不同应用之间,standard、singleTop、singleInstance各自没有区别,只有singleTask不一样,同一应用中不创建新的task,不同应用中有可能会创建新的task。(注:这里用到了“可能”二字,没有用“一定”,是因为这与taskAffinity属性有关,如果设置了此属性,就会在该属性对应的task中启动实例,否则,会创建新的task)。

本文所述情况没有用到Intent标志、taskAffinity属性,如果加入,情况又不一样,在下篇文章Activity栈Stack、Task会介绍。

同分类推荐文章

  1. 「置顶」我做了什么 (2026-05-05 12:13:28)
  2. 万字长文推演:手机不再从 App 开始,Agent OS 如何接管任务入口 (2026-04-28 14:57:22)
  3. Android Perfetto 系列 10 - Binder 调度与锁竞争 (2025-11-16 15:33:30)

查看更多 移动开发 文章 →

建议继续学习

  1. 情绪版(Mood board)操作流程的新思考 (累计阅读 41,756)
  2. android 开发入门 (累计阅读 19,530)
  3. Android 连接SSID隐藏网络以及 LEAP 认证的方法 (累计阅读 9,540)
  4. 让安卓手机通过代理翻墙的方法 (累计阅读 9,117)
  5. 手机产品设计方向 (累计阅读 7,954)
  6. 实时监控Android设备网络封包 (累计阅读 6,558)
  7. Eclipse开发Android应用程序入门:重装上阵 (累计阅读 6,463)
  8. 基于 PhoneGap 与 Java 开发的 Android 应用的性能对比 (累计阅读 6,411)
  9. Android用户界面设计:表格布局 (累计阅读 6,187)
  10. Windows下使用VMware安装Android (累计阅读 5,633)