android - 如何多次更改firebase数据库中的单个值?
问题描述
我试图将 true 和 false 的值更改为相反的值,因此如果数据库中的值为 true,则需要将其更改为 false,如果为 false,则更改为 true。
它在我第一次按下按钮时起作用,但如果我再次按下按钮,它会不停地变化,直到应用程序崩溃。
这是我用来更改值的代码:
package com.example.myapplication.adapters
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.Model.CategoryModel
import com.example.myapplication.R
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
class Category(private val listCategory: MutableList<CategoryModel>) :
RecyclerView.Adapter<Category.ViewHolder>() {
val mAuth = FirebaseAuth.getInstance()
val database = FirebaseDatabase.getInstance()
var currentUid = mAuth.currentUser?.uid
val myRef = database.getReference("User-following").child(currentUid!!)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val v = inflater.inflate(R.layout.category_layout, parent, false)
return ViewHolder(v)
}
private fun fetchNotificationStatus(category: String, b: Boolean) {
var status = if (b) {
"true"
} else {
"false"
}
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (childSnapshot in snapshot.children) {
val key = childSnapshot.key
if (childSnapshot.child("category").value == category) {
myRef.child(key!!).child("notifications").setValue(status)
return
}
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database Error", error.toString())
}
})
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var category: TextView = itemView.findViewById(R.id.category)
var remove: Button = itemView.findViewById(R.id.remove)
val alert: CheckBox = itemView.findViewById(R.id.alert)
init {
alert.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
val cat = category.text
if (alert.isChecked) {
Snackbar.make(itemView,
"${category.text} has been added to your notifications list",
Snackbar.LENGTH_LONG)
.show()
fetchNotificationStatus(cat as String, true)
} else {
Snackbar.make(itemView,
"${category.text} has been removed from your notifications list",
Snackbar.LENGTH_LONG)
.show()
fetchNotificationStatus(cat as String, false)
}
}
}
}
因此,当您第一次按下复选框时,它会从
false -> True or from true -> false
但是如果您再次按下复选框,它会不断变化
(false -> true -> false -> true -> false ...)
并且在您关闭应用程序或按下另一个导致应用程序崩溃的按钮之前不会停止更改
我该如何解决这个问题,以便每次按下复选框时它只会变为相反的状态?
解决方案
简单的解决方法是使用addListenerForSingleValueEvent
而不是addValueEventListener
in fetchNotificationStatus
。使用addListenerForSingleValueEvent
确保侦听器仅获得一个值然后停止侦听。你的 currentaddValueEventListener
一直在监听数据,所以它会被你自己的 write 重新触发,然后它会一次又一次地写入它......
此外,我建议使用查询来查找要修改的节点:
private fun fetchNotificationStatus(category: String, b: Boolean) {
var status = if (b) {
"true"
} else {
"false"
}
Query query = myRef.orderByChild("category").equalTo(category);
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (childSnapshot in snapshot.children) {
childSnapshot.getRef().child("notifications").setValue(status)
// might be able to do .ref. instead of .getRef().
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database Error", error.toString())
}
})
}
使用这样的查询可以减少您的应用读取的数据量,从而降低客户端和服务器上的带宽使用/成本。
推荐阅读
- flutter - 如何在 Flutter 中缩小和扩展 Wrap 小部件?
- python - `tiny_malloc_from_free_list` 让我的指针为 `NULL`?
- vba - 在 VBA 中缩短 Like 语句
- authorization - 拒绝在 asmx 上对不在公司的 IP 地址访问某些方法
- c# - 创建 ActionFilter 以排除 WebAPI 中的 NULL 值
- c# - 使用 Invoke 从其他类调用函数
- sql - Postgres 10:根据选择查询结果引发异常或执行更新
- joomla - JInstaller: :Install: 找不到 XML 安装文件
- sql - 根据现有列选择逗号分隔的字符串
- python - Python 3 正则表达式提取字符串的一部分