1.2 Activity的启动模式

四种启动模式

Activity会保存在Activity栈中,按back键,Activity会按照“后进先出”的顺序退栈,当栈中没有Activity时,系统会回收这个任务栈。
默认情况下,Activity使用默认的启动模式,多次启动同一个Activity,系统会重复创建多个实例。Android提供了4种启动模式来修改系统的默认行为。
standard、singleTop、singleTask和singleInstance

  • standard:标准模式,系统的默认模式。每次启动 Activity 都创建一个新的实例,不管这个实例是否已经存在。创建实例,会走 Activity 的onCreate、onStart、onResume方法
    这是一个多实例实现,一个 Activity 栈中可以有多个实例,每个实例也可以属于不同的 Activity 栈

  • singleTop:栈顶复用模式。如果新的 Activity 已经位于栈顶,Activity 不会被重建,会回调它的 onNewIntent 方法,不会回调 onCreate 和 onStart 方法。如果新的 Activity 实例存在于 Activity 栈中,但是不在栈顶,还是会创建新的实例。

  • singleTask:栈内复用,是一种单例模式。这种模式下,只要 Activity 在一个栈中存在,那么多次启动该 Activity 都不会重新创建实例,会回调 onNewIntent 方法。
    具有 singleTask 模式的 Activity A 请求启动,系统先寻找是否存在 A 想要的任务栈:
    如果不存在,创建一个任务栈,创建 A 的实例,把 A 放栈中;
    如果存在,要看该栈中是否有 A 的实例:
    如果存在 A 的实例,把A调到栈顶,并调用它的 onNewIntent 方法;
    如果不存在 A 的实例,创建 A 的实例,把 A 压入栈中
    如果 Activity D 以 singleTask 模式启动,需要的任务栈是 S1,并且当前 Activity 栈 S1 的情况是 ADBC,C 在栈顶,系统会把 D 切换到栈顶并调用 onNewIntent 方法,singleTask 有 clearTop 的效果,将 D 切换到栈顶,所有在 D 上边的 Activity B C 全部出栈,S1 的栈中为 AD

  • singleInstance 单例模式。除了具有 singleTask 的特性外,具有 singleInstance 的 Activity 单独位于一个 Activity 栈中。
    Activity A是 singleInstance 模式,当 A 启动后,系统会为它创建一个新的任务栈,然后 A 独自在这个任务栈中,后续请求 Activity A,都不会新建 Activity A,除非这个任务栈被系统销毁。

这里写图片描述

有2个栈,前台Activity栈存的是 AB,后台Activity栈存的是 CD,启动模式是 singleTask。
请求启动D,后台任务栈被切换到前台,顺序变成了 ABCD,按 back,会一一出栈。
如果请求启动的 不是 D,而是 C,如下图
这里写图片描述

  • 什么是Activity的任务栈?
    从一个参数说起:TaskAffinity,标识了一个Activity所需要的任务栈的名字。默认情况下,Activity 的任务栈名字是应用包名,可以为每个 Activity 指定 TaskAffinity。
    TaskAffinity 属性和 singleTask 模式或者 allowTaskReparenting 属性配对使用。
    任务栈分为 前台任务栈和后台任务栈,后台任务栈中的 Activity 处于暂停状态,用户可以通过切换 将后台任务栈再次调用到前台。

    • TaskAffinity 和 singleTask 配对使用时
      当 Activity 以 singleTask 模式启动时,TaskAffinity 保存的该 Activity 当前任务栈的名字,待启动的Activity会运行在 名字和 TaskAffinity 相同的任务栈中。

    • TaskAffinity 和 allowTaskReparenting 结合使用
      应用 A 启动应用 B 的Activity b,如果 Activity b 的 allowTaskReparenting 属性为 true,那么 当应用 B 被启动后,Activity b 会从 应用 A 的任务栈 转移到 应用 B 的任务栈。
      也就是说 应用 A 启动了 应用 B 的Activity b, 此时 b 在 A 的任务栈中,按 Home 键回到桌面,再单击B的图标,这个时候打开的Activity 不是B 的 MainActivity,显示的是 被 A 启动的 Activity b。Activity b 从 A 的任务栈 转到了 B 的任务栈。

设置Activity的启动模式

  • manifest中设置
    <activity android:name=".BActivity"
            android:launchMode="singleTask">
  • 代码中Intent设置flag
    Intent intent = new Intent();
    intent.setClass(MainActivity.this, BActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);

Manifest 和 代码 同时 设置启动模式时,以代码为准。
Manifest中 没有 Intent.FLAG_ACTIVITY_CLEAR_TOP 标识;代码里没有 singleInstance

对比singleTask与默认模式
1。singleTask
Mainifest

        <activity android:name=".MainActivity"
                android:configChanges="orientation|screenSize"
                android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

MainActivity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, MainActivity.class);
                intent.putExtra("time", System.currentTimeMillis());
                startActivity(intent);

            }
        });
        Log.d(TAG, "onCreate::");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d(TAG, "onNewIntent::, time = " + intent.getLongExtra("time", 0));
    }

log

//第一次运行
01-09 11:43:57.279 22595-22595/? D/MainActivity_A: onCreate::
01-09 11:43:57.284 22595-22595/? D/MainActivity_A: onStart::
01-09 11:43:57.287 22595-22595/? D/MainActivity_A: onResume::
//点击button
01-09 11:44:04.184 22595-22595/? D/MainActivity_A: onPause::
01-09 11:44:04.184 22595-22595/? D/MainActivity_A: onNewIntent::, time = 1483933444173
01-09 11:44:04.186 22595-22595/? D/MainActivity_A: onResume::
//点击button
01-09 11:44:05.602 22595-22595/? D/MainActivity_A: onPause::
01-09 11:44:05.602 22595-22595/? D/MainActivity_A: onNewIntent::, time = 1483933445593
01-09 11:44:05.606 22595-22595/? D/MainActivity_A: onResume::
//点击button
01-09 11:44:07.035 22595-22595/? D/MainActivity_A: onPause::
01-09 11:44:07.035 22595-22595/? D/MainActivity_A: onNewIntent::, time = 1483933447025
01-09 11:44:07.037 22595-22595/? D/MainActivity_A: onResume::

adb shell dumpsys activity activities > d:\temp\activity_single.txt

    Running activities (most recent first):
      TaskRecord{44d3a3a #828 A=activity.jieqiong.com.activity U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{a01bb0d u0 activity.jieqiong.com.activity/.MainActivity t828}

2。默认模式,去掉Manifest中的android:launchMode=”singleTask”

        <activity android:name=".MainActivity"
                android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

log

//第一次运行
01-09 11:49:45.197 27333-27333/? D/MainActivity_A: onCreate:: test = 
01-09 11:49:45.203 27333-27333/? D/MainActivity_A: onStart::
01-09 11:49:45.214 27333-27333/? D/MainActivity_A: onResume::
//点击button
01-09 11:49:47.691 27333-27333/? D/MainActivity_A: onPause::
01-09 11:49:47.718 27333-27333/? D/MainActivity_A: onCreate:: test = 
01-09 11:49:47.719 27333-27333/? D/MainActivity_A: onStart::
01-09 11:49:47.720 27333-27333/? D/MainActivity_A: onResume::
01-09 11:49:48.115 27333-27333/? D/MainActivity_A: onSaveInstanceState:: save test = testString
01-09 11:49:48.118 27333-27333/? D/MainActivity_A: onStop::
//点击button
01-09 11:49:49.007 27333-27333/? D/MainActivity_A: onPause::
01-09 11:49:49.051 27333-27333/? D/MainActivity_A: onCreate:: test = 
01-09 11:49:49.052 27333-27333/? D/MainActivity_A: onStart::
01-09 11:49:49.054 27333-27333/? D/MainActivity_A: onResume::
01-09 11:49:49.470 27333-27333/? D/MainActivity_A: onSaveInstanceState:: save test = testString
01-09 11:49:49.471 27333-27333/? D/MainActivity_A: onStop::
//点击button
01-09 11:49:50.365 27333-27333/? D/MainActivity_A: onPause::
01-09 11:49:50.401 27333-27333/? D/MainActivity_A: onCreate:: test = 
01-09 11:49:50.403 27333-27333/? D/MainActivity_A: onStart::
01-09 11:49:50.407 27333-27333/? D/MainActivity_A: onResume::
01-09 11:49:50.844 27333-27333/? D/MainActivity_A: onSaveInstanceState:: save test = testString
01-09 11:49:50.845 27333-27333/? D/MainActivity_A: onStop::

adb shell dumpsys activity activities > d:\temp\activity.txt

    Running activities (most recent first):
      TaskRecord{21795c4 #829 A=activity.jieqiong.com.activity U=0 StackId=1 sz=4}
        Run #3: ActivityRecord{b7d9564 u0 activity.jieqiong.com.activity/.MainActivity t829}
        Run #2: ActivityRecord{77d3a1e u0 activity.jieqiong.com.activity/.MainActivity t829}
        Run #1: ActivityRecord{5c6e3b3 u0 activity.jieqiong.com.activity/.MainActivity t829}
        Run #0: ActivityRecord{830e7ba u0 activity.jieqiong.com.activity/.MainActivity t829}
  • singleTask举例

    1. 默认模式的 MainActivity 按钮 BtnA,点击 打开 BActivity(singleTop,指定栈为com.jieqiong.task1)
    2. 点击BActivity的按钮BtnB,打开 CActivity(singleTop,指定栈为com.jieqiong.task1)
    3. 点击CActivity的按钮BtnC,打开MainActivity
    4. 点击MainActivity的按钮BtnA,打开BActivity
    5. 按back,直至回到桌面
        <activity
                android:name=".MainActivity"
                android:configChanges="orientation|screenSize"
                android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".BActivity"
                android:launchMode="singleTask"
                android:taskAffinity="com.jieqiong.task1">
        </activity>
        <activity android:name=".CActivity"
                android:launchMode="singleTask"
                android:taskAffinity="com.jieqiong.task1">
        </activity>

MainActivity——BActivity——CActivity——MainActivity对应的Activity栈如下:
此时是2个栈,com.jieqiong.task1中存从是BCMain,B在栈底及 包名栈中存的是Main。
adb shell dumpsys activity activities

//BActivity,CActivity是singleTask的,栈名是com.jieqiong.task1,通过CActivity启动MainActivity,此时的MainActivity在栈task1中,不是包名的栈
    Running activities (most recent first):
      TaskRecord{9598382 #894 A=com.jieqiong.task1 U=0 StackId=1 sz=3}
        Run #6: ActivityRecord{2fa1a85 u0 activity.jieqiong.com.activity/.MainActivity t894}
        Run #5: ActivityRecord{f23f6b3 u0 activity.jieqiong.com.activity/.CActivity t894}
        Run #4: ActivityRecord{8ff2e5e u0 activity.jieqiong.com.activity/.BActivity t894}
        //第一次启动的MainActivity,模式是standard,栈是包名
      TaskRecord{ef33ad0 #893 A=activity.jieqiong.com.activity U=0 StackId=1 sz=1}
        Run #3: ActivityRecord{b53b587 u0 activity.jieqiong.com.activity/.MainActivity t893}
      TaskRecord{ea055ce #834 A=com.android.settings U=0 StackId=1 sz=3}
        Run #2: ActivityRecord{67aa406 u0 com.android.settings/.SubSettings t834}
        Run #1: ActivityRecord{cb7a39 u0 com.android.settings/.SubSettings t834}
        Run #0: ActivityRecord{aaa95a9 u0 com.android.settings/.Settings t834}

此时点击MainActivity的BtnB,要启动B,会将com.jieqiong.task1栈中的B移到顶部,上边的C和Main先出栈,该栈中只剩下B,按Back,B出栈,task1栈清空;退到 包名的栈,显示MainActivity,按Back,MainActivity从包名栈中出栈,回到桌面。

启动Activity的flag

//同一个任务栈中位于该Activity上边的,都要出栈,一般和FLAG_ACTIVITY_NEW_TASK配合使用,如果该Activity实例已存在,会调用onNewIntent方法。
//如果该Activity使用的是standard模式,它和它上边的Activity都出栈,系统创建新的实例,放入栈顶
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//该Activity不会出现在历史Activity列表中,等同于在Manifest中为该Activity加 android:excludeFromRecents="true"
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值