【问题标题】:Why when update data in firebase the data in recyclerView duplicated为什么在firebase中更新数据时recyclerView中的数据重复
【发布时间】:2021-07-17 00:58:36
【问题描述】:

如果我对 firebase 有任何更改,例如删除、更新。如果发生任何这些 CRUD,recyclerView 中的数据就会重复,因此我添加了临时 swipeRefresh 以刷新活动,但此解决方案没有意义。

下图解释了我在 firebase 中更新数据时以及在 RecyclerView 中发生了什么

MainDashBoard.kt

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
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout

class MainDashBoard : AppCompatActivity(), OnItemPatientClickListener{
    data class PatientDataItem(val patientName: String, val patientMessage: String)
    private lateinit var auth: FirebaseAuth
    lateinit var swipeRefreshLayout: SwipeRefreshLayout
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main_dash_board)
        var database = FirebaseDatabase.getInstance().reference
        var  patientDataItems  = ArrayList<PatientDataItem>()
        val patientRecycler = findViewById<RecyclerView>(R.id.patient_recycler)
        val patienDashboardprogressBar = findViewById<ProgressBar>(R.id.patientDashboardprogressBar)
        val noDataMain = findViewById<TextView>(R.id.no_data_main_dashboard)
        swipeRefreshLayout = findViewById(R.id.swipe)
        patientRecycler.layoutManager = LinearLayoutManager(this)
        patientRecycler.adapter = MainDashboardAdapter(patientDataItems, this)

        auth = FirebaseAuth.getInstance()
        val user = auth.currentUser

        val patientsListener = object : ValueEventListener {
            override fun onDataChange(p0: DataSnapshot) {
                val patients = p0.child("users").child(user!!.uid)
                if (p0.value == null ){
                    noDataMain.visibility = View.VISIBLE
                }else{
                    noDataMain.visibility = View.GONE
                    for (i in p0.children){
                        var patientName = i.key.toString()
                        var patientMessage = i.value.toString()

                        patientDataItems.add(PatientDataItem(patientName, patientMessage))
                    }
                }

                patientRecycler.scrollToPosition(patientDataItems.size-1)
                patienDashboardprogressBar.visibility = View.GONE

            }
            override fun onCancelled(error: DatabaseError) {
                println("error")
            }
        }


        database.child("location").child("users").child(user!!.uid).addValueEventListener(patientsListener)
//           database.child("location").addValueEventListener(postListener)
        swipeRefreshLayout.setOnRefreshListener {
            startActivity(intent);
            Handler(Looper.getMainLooper()).postDelayed(Runnable {
                swipeRefreshLayout.isRefreshing = false
            }, 4000)
        }

    }
    override fun onItemClick(patientDataItems: PatientDataItem) {
        val patientMacAddressName = patientDataItems.patientName

        val dashboardIntent = Intent(this, DashboardActivity::class.java)
        dashboardIntent.putExtra("macAddressNamePatient", patientMacAddressName)
        startActivity(dashboardIntent)

    }
}


MainDashBoardAdapter.kt

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.example.ard_here.R

class MainDashboardAdapter(private val patientDataSet: ArrayList<MainDashBoard.PatientDataItem>,
                           private val onPatientClickListener: OnItemPatientClickListener): RecyclerView.Adapter<MainDashboardAdapter.PatientCustomHolder>(){


    override fun getItemCount(): Int {
        return patientDataSet.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PatientCustomHolder {
        var layoutInflater = LayoutInflater.from(parent?.context)
        var cellForRow = layoutInflater.inflate(R.layout.main_patient_layout, parent, false)
        return PatientCustomHolder(cellForRow)
    }
    override fun onBindViewHolder(holder: PatientCustomHolder, position: Int) {
        holder.bindItems(patientDataSet[position])
        holder.patientLayout.setOnClickListener {
            onPatientClickListener.onItemClick(patientDataSet[position])
        }
    }


    class PatientCustomHolder(v: View): RecyclerView.ViewHolder(v){
        val patientLayout: ConstraintLayout = v.findViewById(R.id.patient_layout)
        val patientName: TextView = v.findViewById(R.id.patient_name)
        val patientMessage : TextView = v.findViewById(R.id.patient_message)
        fun bindItems(data_item: MainDashBoard.PatientDataItem){
            patientName.text = data_item.patientName
            patientMessage.text = data_item.patientMessage

        }
    }
}

OnItemPatientClickListener.kt

interface OnItemPatientClickListener {
    fun onItemClick(patientDataItems: MainDashBoard.PatientDataItem)
}

【问题讨论】:

    标签: android firebase kotlin firebase-realtime-database android-recyclerview


    【解决方案1】:

    由于您正在使用addValueEventListener 读取数据,这意味着:

    1. 路径中的数据会立即从数据库中读取,并传递给您的onDataChange
    2. 客户端继续监视路径,如果有任何变化,它会再次调用您的onDataChange,并在路径中包含所有数据。

    在您的onDataChange 中,您只是将数据添加到patientDataItems。第一次加载数据时效果很好,所以上面的#1。但是,如果您添加或更改单个子节点(上面的#2),您会再次在路径中使用 all data 进行调用。因此,您最终会复制视图中的项目。

    最简单的解决方案是在onDataChange 被调用时清除patientDataItems

    override fun onDataChange(p0: DataSnapshot) {
        patientDataItems.clear()
        ...
    

    【讨论】:

    • 我这样做是在更新的情况下不起作用,但在添加它需要最后一个元素并添加它,所以我需要刷新以查看我做了什么
    【解决方案2】:

    清除您的数据容器,然后在 recyclerview 中再次绑定它。 或者你有 mvvm 模式,你可以使用实时数据来观察数据源,如果有任何变化,你的活动将很容易通知并进行一些 ui 更改

    【讨论】:

    • 如果我这样做了,实时数据库有什么好处?
    猜你喜欢
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    • 2015-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多