You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何等待所有FCM主题订阅完成后再启动新Activity?

优化FCM主题批量订阅后跳转Activity的实现

问题背景

从服务器获取需订阅的主题数组,循环逐一订阅FCM主题,希望等待所有订阅完成后再启动新Activity。当前通过判断循环索引是否为数组最后一位来触发启动操作,现有代码如下:

int length = subscribeTo.length();
for (int i = 0; i < length; i++) {
    String sub = null;
    try {
        sub = subscribeTo.get(i).toString();
    } catch (JSONException e) {
        e.printStackTrace();
    }
    int finalI = i;
    JSONObject finalData = data;
    String finalSub = sub;
    FirebaseMessaging.getInstance().subscribeToTopic(sub).addOnCompleteListener(new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
            Log.e("sub", finalSub);
            if (!task.isSuccessful()) {
                Toast.makeText(MainActivity.this, "can't login in", Toast.LENGTH_SHORT).show();
                return;
            }
            Log.e("test", "sub" + finalI);
            if (finalI == length - 1) {
                try {
                    editor.putInt("sub_length", length);
                    editor.putString("restaurant_name", finalData.get("restaurant_name").toString());
                    editor.putString("username", finalData.get("username").toString());
                    editor.putString("password", finalData.get("password").toString());
                    editor.putString("sub" + finalI, finalSub);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                Intent intent = new Intent(MainActivity.this, MainActivity2.class);
                startActivity(intent);
                editor.apply();
                finish();
            }
        }

    });
}

现有代码的问题

  • 逻辑依赖漏洞:仅靠最后一个任务完成触发跳转,若最后一个订阅失败,即使前面所有任务成功也无法跳转,不符合需求。
  • 数据存储不完整:仅存储了最后一个订阅的主题,前面的主题未存入SharedPreferences,属于功能bug。
  • 异常处理缺失:JSON解析失败时仅打印日志,未处理该任务的后续逻辑,可能导致流程阻塞或计数错误。
  • 代码冗余:匿名内部类需要复制多个final变量,代码可读性差。

更优实现方案

方案一:利用Firebase Tasks.whenAll批量等待任务

Firebase的Tasks类提供的whenAll方法可批量等待所有异步任务完成,逻辑清晰且贴合Firebase生态:

// 收集所有订阅任务
List<Task<Void>> taskList = new ArrayList<>();
int length = subscribeTo.length();

for (int i = 0; i < length; i++) {
    try {
        String sub = subscribeTo.get(i).toString();
        Task<Void> subscribeTask = FirebaseMessaging.getInstance().subscribeToTopic(sub);
        taskList.add(subscribeTask);
        
        // 单独处理单个任务的失败
        subscribeTask.addOnFailureListener(e -> {
            Log.e("sub", "订阅主题[" + sub + "]失败: " + e.getMessage());
            Toast.makeText(MainActivity.this, "部分主题订阅失败", Toast.LENGTH_SHORT).show();
        });
    } catch (JSONException e) {
        e.printStackTrace();
        Toast.makeText(MainActivity.this, "主题解析失败", Toast.LENGTH_SHORT).show();
    }
}

// 等待所有任务完成后统一处理
Tasks.whenAll(taskList)
    .addOnCompleteListener(combinedTask -> {
        if (combinedTask.isSuccessful()) {
            // 所有订阅成功,执行存储与跳转
            try {
                editor.putInt("sub_length", length);
                editor.putString("restaurant_name", data.get("restaurant_name").toString());
                editor.putString("username", data.get("username").toString());
                editor.putString("password", data.get("password").toString());
                
                // 存储所有订阅主题
                for (int i = 0; i < length; i++) {
                    String sub = subscribeTo.get(i).toString();
                    editor.putString("sub" + i, sub);
                }
                editor.apply();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            
            Intent intent = new Intent(MainActivity.this, MainActivity2.class);
            startActivity(intent);
            finish();
        } else {
            // 至少一个任务失败
            Toast.makeText(MainActivity.this, "部分主题订阅失败,无法进入应用", Toast.LENGTH_SHORT).show();
        }
    });

方案二:使用Java CountDownLatch(并发场景方案)

若不想依赖Firebase的Tasks类,可使用Java并发包的CountDownLatch实现等待逻辑:

int length = subscribeTo.length();
CountDownLatch latch = new CountDownLatch(length);
boolean[] hasFailure = {false}; // 数组用于在匿名内部类中修改失败状态

for (int i = 0; i < length; i++) {
    try {
        String sub = subscribeTo.get(i).toString();
        FirebaseMessaging.getInstance().subscribeToTopic(sub)
            .addOnCompleteListener(task -> {
                if (!task.isSuccessful()) {
                    Log.e("sub", "订阅主题[" + sub + "]失败");
                    hasFailure[0] = true;
                }
                latch.countDown(); // 任务完成,计数减一
            });
    } catch (JSONException e) {
        e.printStackTrace();
        hasFailure[0] = true;
        latch.countDown(); // 解析失败也要减少计数,避免阻塞
    }
}

// 开启线程等待所有任务完成
new Thread(() -> {
    try {
        latch.await(); // 阻塞直到所有任务完成
        
        // 回到UI线程处理界面逻辑
        runOnUiThread(() -> {
            if (!hasFailure[0]) {
                // 所有订阅成功,存储数据并跳转
                try {
                    editor.putInt("sub_length", length);
                    editor.putString("restaurant_name", data.get("restaurant_name").toString());
                    editor.putString("username", data.get("username").toString());
                    editor.putString("password", data.get("password").toString());
                    
                    for (int i = 0; i < length; i++) {
                        String sub = subscribeTo.get(i).toString();
                        editor.putString("sub" + i, sub);
                    }
                    editor.apply();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                
                Intent intent = new Intent(MainActivity.this, MainActivity2.class);
                startActivity(intent);
                finish();
            } else {
                Toast.makeText(MainActivity.this, "部分主题订阅失败", Toast.LENGTH_SHORT).show();
            }
        });
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:01:10