Firebase Realtime Database:存储多评分避免覆盖及取值计算平均值
解决Firebase Realtime Database多评分存储与平均值计算问题
一、实现多值存储(避免覆盖原有数据)
你当前用setValue()方法会直接替换目标节点的全部内容,所以每次提交新评分都会覆盖之前的数据。要存储多个评分,需要在/general/$position节点下为每个评分生成唯一子节点,用Firebase的push()方法就能自动生成不重复的ID:
修改按钮点击事件里的存储代码:
val button = dialog.findViewById<View>(R.id.menu_rate) as Button button.setOnClickListener { val simpleRatingBar = dialog.findViewById<View>(R.id.ratingBar) as RatingBar val ratingNumber = simpleRatingBar.rating Toast.makeText(this, "You rated this $ratingNumber stars!", Toast.LENGTH_SHORT).show() // 直接存储Float类型(比字符串更方便后续计算),用push()生成唯一子节点 myRef.push().setValue(ratingNumber) .addOnSuccessListener { Toast.makeText(this, "success", Toast.LENGTH_SHORT).show() } }
修改后的数据结构会变成这样(每个评分对应一个唯一键的子节点):
general |--- [position值] |--- -Nabc123: 4.5 |--- -Ndef456: 3.0 |--- -Ngih789: 5.0
二、获取所有评分并计算平均值
要获取该节点下的所有评分,监听myRef的ValueEvent,遍历所有子节点的值后计算总和与平均值:
// 监听评分节点的实时变化,获取所有评分 myRef.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { var totalRating = 0.0f var ratingCount = 0 // 遍历所有子节点,累加评分 for (childSnapshot in snapshot.children) { val rating = childSnapshot.getValue(Float::class.java) ?: continue totalRating += rating ratingCount++ } // 计算平均值(避免除以0的情况) val averageRating = if (ratingCount > 0) totalRating / ratingCount else 0.0f // 在这里将平均值展示到应用中,比如更新TextView // averageTextView.text = String.format("平均评分: %.1f", averageRating) } override fun onCancelled(error: DatabaseError) { // 处理数据加载失败的情况 Toast.makeText(this@YourActivity, "加载评分失败", Toast.LENGTH_SHORT).show() } })
补充说明
- 如果坚持要存储字符串类型,获取时把
childSnapshot.getValue(String::class.java)转成Float即可(比如rating.toFloat()),但更推荐直接存储数值类型,减少转换步骤和出错概率。 - 若不需要实时监听评分变化,可改用
addListenerForSingleValueEvent,只获取一次数据。
内容的提问来源于stack exchange,提问作者Joshu
相关产品推荐
相关产品推荐

