You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何确保Android中每个Activity同一时间仅能拥有一个子Activity?

解决Activity重复启动与多子Activity同时创建的问题

先把咱们要解决的核心需求理清楚:

  • 避免创建同类型重复子Activity:比如用户快速点击启动Activity B的按钮,不会连续打开多个B实例
  • 禁止同时创建多个不同子Activity:比如用户连续点击启动B和C的按钮,不会同时打开B和C两个不同的子Activity

一、针对需求1:避免同类型重复子Activity

你当前用的Intent.FLAG_ACTIVITY_CLEAR_TOP能实现“回到已有实例”的效果,但结合Intent.FLAG_ACTIVITY_SINGLE_TOP会更贴合“快速点击不重复创建”的场景:

  • FLAG_ACTIVITY_SINGLE_TOP:如果目标Activity已经处于栈顶,系统不会创建新实例,而是调用该Activity的onNewIntent()方法,完美解决快速点击重复创建的问题
  • FLAG_ACTIVITY_CLEAR_TOP:如果目标Activity存在于栈中但不在顶,系统会把它上面的所有Activity都finish,再把它拉到栈顶(适合需要回到已有实例而非新建的场景)

如果你的场景只是“快速点击不重复创建同类型Activity”,单独用FLAG_ACTIVITY_SINGLE_TOP就足够;如果要确保每次启动都回到同一个实例(不管它在栈的哪个位置),就把两个Flag结合使用。

二、针对需求2:禁止同时创建多个不同子Activity

这个需要给当前Activity加一个状态标记,用来判断是否正在启动子Activity,避免连续点击不同按钮触发多个启动逻辑。具体步骤如下:

  1. 在当前Activity(比如Activity A)中添加一个成员变量,标记是否正在启动Activity
  2. 点击按钮启动Activity前,先检查这个标记:如果标记为true,说明已有启动流程在进行,直接返回;如果为false,则将标记设为true,再执行启动逻辑
  3. 在子Activity返回时(onActivityResult),或者当前Activity失去焦点时(onPause),将标记重置为false,确保下次可以正常启动

完整示例代码(以Activity A为例)

public class ActivityA extends AppCompatActivity {
    // 标记是否正在启动子Activity
    private boolean isActivityLaunching = false;
    private static final int REQUEST_CODE_B = 1001;
    private static final int REQUEST_CODE_C = 1002;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);

        Button buttonStartB = findViewById(R.id.btn_start_b);
        Button buttonStartC = findViewById(R.id.btn_start_c);

        buttonStartB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 先检查是否正在启动其他Activity,避免同时创建多个子Activity
                if (isActivityLaunching) {
                    return;
                }
                isActivityLaunching = true;

                Intent myIntent = new Intent(ActivityA.this, ActivityB.class);
                // 结合Flag解决同类型重复创建问题
                myIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivityForResult(myIntent, REQUEST_CODE_B);
            }
        });

        buttonStartC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isActivityLaunching) {
                    return;
                }
                isActivityLaunching = true;

                Intent myIntent = new Intent(ActivityA.this, ActivityC.class);
                myIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivityForResult(myIntent, REQUEST_CODE_C);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 子Activity返回后,重置启动标记
        isActivityLaunching = false;
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 额外保险:如果当前Activity失去焦点(比如启动了子Activity),也重置标记
        // 避免某些异常情况(比如子Activity启动失败)导致标记一直为true
        isActivityLaunching = false;
    }
}

补充说明

  • 对于Activity B启动Activity D的场景,完全可以复用这个逻辑:给Activity B添加isActivityLaunching标记,启动D前做检查,同时给Intent加上对应的Flag
  • 如果不需要startActivityForResult(比如不需要子Activity返回数据),可以用startActivity(),然后在onPause里重置标记即可

内容的提问来源于stack exchange,提问作者AlanSTACK

火山引擎 最新活动