Android中Firebase结合ValueEventListener回调修改数组值的实现方法
如何在Firebase Realtime Database的ValueEventListener中结合回调更新数据?
问题背景
我在Android(Java)中实现了一个从Firebase Realtime Database获取评分数据的方法,同时定义了FirebaseRatingCallback回调接口。由于Firebase操作是异步的,必须通过回调来处理结果,但我不知道如何在ValueEventListener中正确结合回调更新ratingValue[0]的值,之前尝试添加onComplete方法无效,求正确实现方式。
原始方法代码
public static void getInformationWhenInfoButtonIsPressed(FirebaseRatingCallback callback, float[] ratingValue, String item) { DatabaseReference rootRef_Firebase; rootRef_Firebase = FirebaseDatabase.getInstance(DataBaseEntries.FIREBASE_URL).getReference(); rootRef_Firebase .child(DataBaseEntries.FIREBASE_NODE_RATINGS_AGGREGATED) .orderByChild(DataBaseEntries.FIREBASE_NAME) .equalTo(item) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { int numberOfRatingsOverall = 0; double tempScoreOverall = 0; for (DataSnapshot ds : dataSnapshot.getChildren()) { float averageRatingOfCurrentDrink = 0; int numberOfRatingsCurrentDrink = 0; if (ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class) != null) { averageRatingOfCurrentDrink = ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class); } if (ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class) != null) { numberOfRatingsCurrentDrink = ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class); numberOfRatingsOverall = numberOfRatingsOverall + numberOfRatingsCurrentDrink; } tempScoreOverall = tempScoreOverall + numberOfRatingsCurrentDrink * averageRatingOfCurrentDrink; } ratingValue[0] = (float) (tempScoreOverall / numberOfRatingsOverall); } @Override public void onCancelled(@NonNull DatabaseError error) { throw error.toException(); } }); ratingValue[0] = (float) (Math.round(ratingValue[0] * 10.0) / 10.0); }
定义的回调接口
public interface FirebaseRatingCallback { void onCallBackRating(boolean dataIsReadFromFirebase); }
错误的尝试代码
我曾尝试在onDataChange内部添加onComplete方法,但没有效果:
public static void getInformationWhenInfoButtonIsPressed(FirebaseRatingCallback callback, float[] ratingValue, String item) { DatabaseReference rootRef_Firebase; rootRef_Firebase = FirebaseDatabase.getInstance(DataBaseEntries.FIREBASE_URL).getReference(); rootRef_Firebase .child(DataBaseEntries.FIREBASE_NODE_RATINGS_AGGREGATED) .orderByChild(DataBaseEntries.FIREBASE_NAME) .equalTo(item) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { int numberOfRatingsOverall = 0; double tempScoreOverall = 0; for (DataSnapshot ds : dataSnapshot.getChildren()) { float averageRatingOfCurrentDrink = 0; int numberOfRatingsCurrentDrink = 0; if (ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class) != null) { averageRatingOfCurrentDrink = ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class); } if (ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class) != null) { numberOfRatingsCurrentDrink = ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class); numberOfRatingsOverall = numberOfRatingsOverall + numberOfRatingsCurrentDrink; } tempScoreOverall = tempScoreOverall + numberOfRatingsCurrentDrink * averageRatingOfCurrentDrink; } public void onComplete(@NonNull Task<Void> task) { ratingValue[0] = (float) (tempScoreOverall/numberOfRatingsOverall); callback.onCallBackRating(true); } } @Override public void onCancelled(@NonNull DatabaseError error) { throw error.toException(); } }); }
正确实现方案
ValueEventListener的onDataChange本身就是异步操作完成后的回调终点,不需要额外添加onComplete方法。正确的做法是在onDataChange内完成数据计算、数组更新和回调调用,同时处理异常场景:
public static void getInformationWhenInfoButtonIsPressed(FirebaseRatingCallback callback, float[] ratingValue, String item) { DatabaseReference rootRef_Firebase = FirebaseDatabase.getInstance(DataBaseEntries.FIREBASE_URL).getReference(); rootRef_Firebase .child(DataBaseEntries.FIREBASE_NODE_RATINGS_AGGREGATED) .orderByChild(DataBaseEntries.FIREBASE_NAME) .equalTo(item) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { int numberOfRatingsOverall = 0; double tempScoreOverall = 0; for (DataSnapshot ds : dataSnapshot.getChildren()) { float averageRatingOfCurrentDrink = 0; int numberOfRatingsCurrentDrink = 0; if (ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class) != null) { averageRatingOfCurrentDrink = ds.child(DataBaseEntries.FIREBASE_AVERAGE_RATING).getValue(Float.class); } if (ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class) != null) { numberOfRatingsCurrentDrink = ds.child(DataBaseEntries.FIREBASE_NUMBER_OF_RATINGS).getValue(Integer.class); numberOfRatingsOverall += numberOfRatingsCurrentDrink; } tempScoreOverall += numberOfRatingsCurrentDrink * averageRatingOfCurrentDrink; } // 处理无数据/评分总数为0的情况,避免除以0异常 if (numberOfRatingsOverall > 0) { ratingValue[0] = (float) (tempScoreOverall / numberOfRatingsOverall); // 保留一位小数 ratingValue[0] = (float) (Math.round(ratingValue[0] * 10.0) / 10.0); callback.onCallBackRating(true); } else { // 无数据时设置默认值,可根据需求调整 ratingValue[0] = 0.0f; callback.onCallBackRating(false); } } @Override public void onCancelled(@NonNull DatabaseError error) { // 回调通知数据获取失败,调用方可在此处理错误 callback.onCallBackRating(false); // 若需抛出异常,建议在回调内统一处理,避免崩溃 // throw error.toException(); } }); }
关键说明
- 所有依赖异步数据的操作(计算、数组更新、回调调用)必须放在
onDataChange内部,因为外部代码会在Firebase返回数据前执行,无法拿到正确结果。 - 必须处理
numberOfRatingsOverall为0的场景,避免运行时除以0异常。 - 在
onCancelled中也要调用回调,通知调用方数据获取失败,确保回调逻辑的完整性。
内容的提问来源于stack exchange,提问作者VanessaF
相关产品推荐
相关产品推荐

