Android Firestore中调用含嵌套Task的方法后如何等待全部加载完成?
如何等待Firestore嵌套异步任务完成后执行后续代码?
你的问题核心在于getRecipe方法目前是异步执行的,但方法本身是void类型,调用者无法感知内部所有Firestore查询(包括食谱查询和批量配料查询)什么时候全部完成。要解决这个问题,我们可以把getRecipe改成返回一个Task<Recipe>,让调用者能通过监听这个Task来等待所有操作完成。
改造思路
- 使用
TaskCompletionSource创建一个可手动控制完成状态的Task,作为方法的返回值。 - 收集所有配料查询的Task,用
Tasks.whenAll等待它们全部完成。 - 在所有任务成功完成后,通知调用者并返回加载好的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
相关产品推荐
相关产品推荐

