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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:45:28