【Android】Activity的启动模式

一、活动的启动模式

1、Activity设置启动模式的两种方式

1.1 设置android:launchMode属性

启动模式的修改在``AndroidManifest.xml`文件中,例如这样:

<activity
          android:name=".FirstActivity"
          android:launchMode="singleTop"
          android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

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

android:launchMode=“singleTop”,这句话指定了Activty的启动模式,不写就是默认启动模式。

1.2 设置Intent Flag

Intent intent=new Intent(this,TransitionActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

通过在开启Activity的时候,通过设置Intent Flag

常用的几个Flag

  • FLAG_ACTIVITY_SINGLE_TOP 其效果和singleTop模式一样

  • FLAG_ACTIVITY_CLEAR_TOP 其效果和singleTask模式一样

  • FLAG_ACTIVITY_NO_HISTORY 其效果是当某个Activity以这种方式启动的时候,其再去启动其他Activity,则该Activity就消失了;比如,A以这种方式启动B,B启动了C,那么Activity的任务栈中就只有AC

  • FLAG_ACTIVITY_NEW_TASK 其效果是启动的activity在一个新的任务栈中,功能和第一种singleInstance模式一样,通常用于在一个没有Activity任务栈的环境里开启一个Activity,就好比我们经常使用的服务里面。

2、Standard——标准模式

【Android】Activity的启动模式_第1张图片

3、SingleTop——栈顶模式

栈顶模式其实很好理解,如果栈顶存在该activity的实例,则复用,不存在新建放入栈顶,它的表现几乎和 上面刚说的标准模式一模一样,栈顶模式的 Activity 实例可以无限多,唯一的区别是如果在栈顶已经有一个相同类型的 Activity 实例,那么 Intent 则不会再去创建一个 Activity,而是通过 onNewIntent() 发送到现有的Activity。

比如应用现在在一个详情页面,而且这个页面启动模式为栈顶模式,这个时候来了一个通知,点击通知正好要跳转到详情页面,那么这个时候任务栈就不会为这个 Activity 再创建一个实例而用已经在栈顶的之前创建好的 Activity 实例。

【Android】Activity的启动模式_第2张图片

3.1 taskAffinity介绍

taskAffinity是指Activity的任务栈亲和度,即任务归属,代表该Activity属于哪个任务栈。使用场景:

1.一般根据taskAffinity重新为Activity选择宿主任务栈(与allowTaskReparenting属性配合使用)

2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据taskAffinity查找或创建一个新的具有对应taskAffinity的任务栈。

注意点:taskAffinity一般singleTask搭配使用,当启动的Activity使用standard、singleTop属性时,如果只设置一个特殊的taskAffinity,但是启动它的时候不设置FLAG_ACTIVITY_NEW_TASK,是不会创建新任务栈。指定singleInstance模式和singleInstancePerTask加上taskAffinity则为新的任务栈命名。

<activity
    android:name=".MainActivity2"
    android:exported="false"
    android:launchMode="singleTask"
    android:taskAffinity="my.one">
    <meta-data
        android:name="android.app.lib_name"
        android:value="" />
activity>

这里就说明了MainActivity2的taskAffinity

my.one

并且launchMode=“singleTask”

4、singleTask——单栈模式

当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

如果当前返回栈中存在,不管是在栈的什么位置,都不会新建,会把它上面的全部出栈,它直接显示在栈顶。

我们给第一个Activity加上这两个语句:

【Android】Activity的启动模式_第3张图片

给跳转的第二个Activity加上这个语句:

【Android】Activity的启动模式_第4张图片

接下来将刚才的 Demo 中的主 Activity 的启动模式改为singleTask,先来看下启动应用后点击跳转到第二个 Activity ,接下来点击再跳转到第一个Activity的log:

2023-07-18 20:21:02.755 13897-13897/com.example.myapplication1 D/TAG: com.example.myapplication1.FirstActivity@78d68d3
2023-07-18 20:21:08.187 13897-13897/com.example.myapplication1 D/TAG: Restart
2023-07-18 20:21:08.707 13897-13897/com.example.myapplication1 D/TAG: Destroy

然后我们重新点击跳转到第二个Activit,此时按Home键回到桌面,然后在打开应用。看看log:

2023-07-18 20:21:13.681 13897-13897/com.example.myapplication1 D/TAG: Destroy
2023-07-18 20:21:13.704 13897-13897/com.example.myapplication1 D/TAG: Restart

是不是不对了,我本来想让应用回到第二个 Activity,但为什么第二个 Activity 直接销毁了?

栈内复用中还有一点要注意,栈内复用模式会将该实例上边的 Activity 全部出栈,将该实例置于栈顶。

【Android】Activity的启动模式_第5张图片

5、singleinstance——单例模式

单例模式,顾名思义,就是新开一个任务栈,该栈内只存放当前实例。比如说项目中语音通话功能,来电显示页面采用的就可以采用单例模式进行处理。

当然还有别的方法来新开任务栈,比如说启动 Activity 的时候加上 FLAG_ACTIVITY_NEW_TASK ,也会开启一个新的任务栈。

在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。

例如:目前有三个活动,指定活动2为singleinstance,此时通过活动一跳转到活动二再跳转到活动三。在活动三界面按下Back,就回到了活动一、这时再按下Back才回到活动二。

【Android】Activity的启动模式_第6张图片

6、singleInstancePerTask——每个任务的单例模式

这个和上面所说的singleInstance基本一致,只不过会为启动的 Activity 新建任务栈。

7、活动的实践

7.1 如何知晓当前所处的活动位置

在当前包下新建一个java类名叫BaseActivity,这个类继承AppCompatActivity类。然后让这个包下其他的Activity继承这个类BaseActivity。

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("Taksr",getClass().getSimpleName());
    }
}

在这个类中重新实现OnCreate方法,并且打印类名。

7.2 随时退出程序

当程序在多个活动里面想要退出是非常不方便的,Back键需要点击多次,Home也只是暂时将程序挂起,并0没有退出程序。思想很简单使用一个List保存所有的Activity,然后依次销毁即可。

新建一个java类ActivityCollertor

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();

    //添加一个活动
    public static void AddActivity(Activity activity){
        activities.add(activity);
    }

    //移除一个活动
    public static void RemoveActivity(Activity activity){
        activities.remove(activity);
    }

    //销毁所有活动
    public static void finishAll(){
        for(Activity activity : activities){
            //检查是否处于销毁状态
            if(!activity.isFinishing()){
                activity.finish();
            }
            activities.clear();
        }
    }
}

在 Android 的 Activity 类中,有一个名为 isFinishing() 的方法,它用于检查当前 Activity 是否在即将被销毁的过程中。当一个 Activity 被调用了 finish() 方法后,它会进入“正在关闭”状态,表示它即将被销毁。在此状态下,isFinishing() 方法会返回 true

接下来修改上一个java类BaseActivity的代码

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("Taksr",getClass().getSimpleName());
        
        //添加当前活动
        ActivityCollector.AddActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        
        //移除已经准备销毁的活动
        ActivityCollector.RemoveActivity(this);
    }
}

接下来只要你想销毁都可以调用ActivityCollector.finishAll()方法即可。例如给一个button按钮使用该方法。

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
        ActivityCollector.finishAll();
    }
});

7.3 优雅的启动活动/传递数据

例如我们使用向上传递数据时,可以对消息进行封装:

private static void actionStart(Context context,String name,String value){
    Intent intent = new Intent(context, FirstActivity.class);
    intent.putExtra(name,value);
    ((Activity)context).setResult(RESULT_OK,intent);
}

【Android】Activity的启动模式_第7张图片

调用起来非常方便一行代码即可,避免代码的复杂性,提高代码的可读性。

你可能感兴趣的:(Android,android,java,开发语言)