Activity的启动模式

109 阅读4分钟

前言

  • AndroidStudio 版本: Android Studio Iguana | 2023.2.1
  • 项目语言: Java
  • JDK版本: 17
  • 对应的android版本:12

整体demon代码地址

前置文章

Activity组件的生命周期 - 掘金 (juejin.cn)

什么是Activity的启动模式

Activity组件的生命周期 - 掘金 (juejin.cn)这篇文章中已经讲到 Activity 的调用其实也是通过 返回栈来实现的,返回栈就是用来存储活动(Activity)的,那么启动模式和返回栈有什么关系呢?这是因为所谓的启动模式就是当启动一个新的 Activity 的时候需要根据返回栈中是否已经存在对应类型的 Activity 而做出不同的行为。

Activity启动模式的配置

Activity 的启动模式配置是在 AndroidManifest.xml 文件中是 <activity> 标签中通过 android:launchMode="standard" 属性来配置的,如下所示

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools">  
  
    <application  
        android:allowBackup="true"  
        android:dataExtractionRules="@xml/data_extraction_rules"  
        android:fullBackupContent="@xml/backup_rules"  
        android:icon="@mipmap/ic_launcher"  
        android:label="@string/app_name"  
        android:roundIcon="@mipmap/ic_launcher_round"  
        android:supportsRtl="true"  
        android:theme="@style/Theme.ADemo"  
        tools:targetApi="31">  
        <activity  
            android:name=".SecondActivity"  
            android:exported="true"
            android:launchMode="standard">  
            <intent-filter>  
                <action android:name="com.example.ademo.MainActivity.MAIN_ACTION" />  
                <action android:name="com.example.ademo.MainActivity.MAIN_ACTION2" />  
                <!-- 这里需要注意的是,即使有其他的 category,默认的category还是需要加上 -->  
                <category android:name="android.intent.category.DEFAULT" />  
                <category android:name="com.example.ademo.MainActivity.CATEGORY_ONE" />  
            </intent-filter>  
        </activity>  
        <activity  
            android:name=".MainActivity"  
            android:exported="true">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
</manifest>

如果没有配置的话,默认就是 standard 类型

Activity启动模式的类型

Activity 的启动模式一共有四种类型

  • standard,这个也是默认值

standard

  • 当启动一个新的 Activity 的时候,不论返回栈中是否存在同类型的 Activity,新的 Activity 都是会加入返回栈的

代码示例

现在在 MainActivity 中再次启动 MainActivity,MainActivity 中的代码示例如下

package com.example.ademo;  
  
import android.content.Intent;  
import android.os.Bundle;  
import android.util.Log;  
import android.view.View;  
import android.widget.Button;  
  
import androidx.activity.EdgeToEdge;  
import androidx.annotation.Nullable;  
import androidx.appcompat.app.AppCompatActivity;  
  
public class MainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
	    // 通过这个日志查看每次创建的 Activity 实例id,如果多次创建是同一个id说明实例相同
        Log.d("MainActivity", "开始创建主Activity" + this);  
        super.onCreate(savedInstanceState);  
        //EdgeToEdge.enable(this);  
        setContentView(R.layout.activity_main);  
        // 通过 findViewById 方法获取 Button 实例  
        Button button = (Button)findViewById(R.id.cus_button);  
        // 给 button 设置点击监听器  
        button.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
	            // 在MainActivity 中再次启动 MainActivity 活动,这样返回栈中就有两个 MainActivity
                startActivity(new Intent(MainActivity.this, MainActivity.class));  
            }  
        });  
    }   
}

在 LogCat 中查看日志如下

2024-04-14 12:09:22.935 16622-16622 MainActivity            com.example.ademo                    D  开始创建主Activitycom.example.ademo.MainActivity@a059f8c
2024-04-14 12:09:36.904 16622-16622 MainActivity            com.example.ademo                    D  开始创建主Activitycom.example.ademo.MainActivity@4bc86d1

可以看到两次的对象是不同的,这就是 standard 模式,即只要是新启动 Activity,不论返回栈中是否存在,都会创建一个新的 Activity 对象放入返回栈中

singleTop

  • 当活动的启动模式指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例
  • 对于 MainActivity 还是使用上面的代码不变,只需要将 AndroidManifest.xml 中的 MainActivity 的启动模式修改成 singleTop 然后再次验证即可,此时会发现不论点击多少次 Button, MainActivity 中的 onCreate 方法只会被调用一次,这是因为当前栈顶的 Activity 就是 MainActivity, 当我们点击 MainActivity 中的 Button 去创建 MainActivity 的时候是直接使用栈顶的 MainActivity 而不是新创建一个 Activity 放入返回栈
<activity  
    android:name=".MainActivity"  
    android:exported="true"  
    android:launchMode="singleTop">  
    <intent-filter>  
        <action android:name="android.intent.action.MAIN" />  
        <category android:name="android.intent.category.LAUNCHER" />  
    </intent-filter>  
</activity>

singleTask

  • singleTop 模式是只有即将要创建的 Activity 在栈顶的时候才会复用栈顶的 Activity,如果即将要启动的 Activity 不是在栈顶的时候还是会创建新的 Activity
  • 使用 singleTask 则可以做到即使即将要创建的 Activity 不是在栈顶,但是在返回栈中也是存在的,那么就会将对应 Activity 前面的那些 Activity 都弹出栈,这样一来这个 Activity 就是会在栈顶了,只有在返回栈中没有发现对应的 Activity 才会去创建对应的 Activity

singleInstance

  • singleInstance 模式实际是新创建一个返回栈来管理对应的 Activity
  • 正常模式下新创建一个 Activity 是直接将对应的 Activity 添加到原本的返回栈中即可,但是对于使用 singleInstance 启动模式的 Activity 则是将这个 Activity 放入在一个新的返回栈中