首页 > 解决方案 > 如何多次更改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 ...) 

并且在您关闭应用程序或按下另一个导致应用程序崩溃的按钮之前不会停止更改

我该如何解决这个问题,以便每次按下复选框时它只会变为相反的状态?

标签: androidkotlinfirebase-realtime-database

解决方案


简单的解决方法是使用addListenerForSingleValueEvent而不是addValueEventListenerin 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())
        }
    })
}

使用这样的查询可以减少您的应用读取的数据量,从而降低客户端和服务器上的带宽使用/成本。


推荐阅读