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

Android Firestore中调用含嵌套Task的方法后如何等待全部加载完成?

如何等待Firestore嵌套异步任务完成后执行后续代码?

你的问题核心在于getRecipe方法目前是异步执行的,但方法本身是void类型,调用者无法感知内部所有Firestore查询(包括食谱查询和批量配料查询)什么时候全部完成。要解决这个问题,我们可以把getRecipe改成返回一个Task<Recipe>,让调用者能通过监听这个Task来等待所有操作完成。

改造思路

  1. 使用TaskCompletionSource创建一个可手动控制完成状态的Task,作为方法的返回值。
  2. 收集所有配料查询的Task,用Tasks.whenAll等待它们全部完成。
  3. 在所有任务成功完成后,通知调用者并返回加载好的Recipe对象;如果任何一步失败,传递异常信息。

修改后的代码

public static Task<Recipe> getRecipe(DocumentReference DR) {
    TaskCompletionSource<Recipe> taskCompletionSource = new TaskCompletionSource<>();

    // 第一步:获取食谱主数据
    DR.get().addOnCompleteListener(recipeTask -> {
        if (recipeTask.isSuccessful() && recipeTask.getResult() != null) {
            Recipe recipe = new Recipe();
            recipe.addStuff(...);
            recipe.addMoreStuff(...);
            recipe.addEvenMoreStuff(...);

            // 第二步:收集所有配料查询任务
            List<Task<DocumentSnapshot>> ingredientTasks = new ArrayList<>();
            for (DocumentReference ingredientRef : ingredients) { // 这里假设ingredients是从食谱文档中获取的配料引用列表
                Task<DocumentSnapshot> ingredientQuery = ingredientRef.get();
                
                ingredientQuery.addOnCompleteListener(ingredientTask -> {
                    if (ingredientTask.isSuccessful() && ingredientTask.getResult() != null) {
                        // 将配料数据添加到Recipe对象中
                        Ingredient ingredient = ingredientTask.getResult().toObject(Ingredient.class);
                        recipe.addIngredient(ingredient);
                    } else {
                        // 如果某个配料查询失败,直接标记整个任务失败
                        taskCompletionSource.setException(ingredientTask.getException());
                    }
                });
                
                ingredientTasks.add(ingredientQuery);
            }

            // 等待所有配料查询完成后,执行后续操作
            Tasks.whenAll(ingredientTasks)
                .addOnSuccessListener(unused -> {
                    // 将加载好的食谱存入本地数据库
                    addRecipe(recipe);
                    // 通知调用者:所有任务完成,返回Recipe
                    taskCompletionSource.setResult(recipe);
                })
                .addOnFailureListener(exception -> {
                    // 任何任务失败时,传递异常
                    taskCompletionSource.setException(exception);
                });
        } else {
            // 食谱主查询失败,传递异常
            taskCompletionSource.setException(recipeTask.getException());
        }
    });

    // 返回Task,供调用者监听
    return taskCompletionSource.getTask();
}

调用方式

其他类调用getRecipe时,只需监听返回的Task,就能在所有加载操作完成后执行后续代码:

getRecipe(targetRecipeDocRef)
    .addOnSuccessListener(loadedRecipe -> {
        // 所有内容都加载完成了!在这里执行你的后续逻辑
        processLoadedRecipe(loadedRecipe);
    })
    .addOnFailureListener(error -> {
        // 处理加载失败的情况,比如提示用户
        Log.e("RecipeLoader", "Failed to load recipe and ingredients", error);
    });

关键说明

  • TaskCompletionSource相当于一个"任务控制器",让我们能在嵌套的异步回调中手动标记任务的成功或失败。
  • Tasks.whenAll会等待传入的所有Task完成,不管单个任务成功还是失败;如果你需要确保所有配料查询都成功才继续,可以改用Tasks.whenAllSuccess。
  • 改造后,调用者不需要关心内部的嵌套异步逻辑,只需要和一个Task交互,代码结构更清晰,也能正确等待所有操作完成。

内容的提问来源于stack exchange,提问作者T. Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 15:22:50