Reputation:
if I any change in firebase like delete, update. The data in recyclerView is duplicated if any of those CRUD occur, so I added temporary swipeRefresh to refresh the activity but this solution doesn't make sense.
This image below explain when I update data in firebase and what happend in 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)
}
Upvotes: 0
Views: 673
Reputation: 34
clear your data container then bind it again in recyclerview. or you have mvvm pattern, you can use live data to observe data source and if there is any changes, your activity will easily notified and make some ui changes
Upvotes: 1
Reputation: 598708
Since you're reading the data with addValueEventListener
, which means that:
onDataChange
.onDataChange
again with all data at the path.In your onDataChange
you're only ever adding data to patientDataItems
. That works well the first time the data is loaded, so #1 above. But if you add or change a single child node (#2 above), you get called with all data at the path again. So that's when you end up duplicating the items in the view.
The simplest solution is to clear patientDataItems
whenever onDataChange
get called:
override fun onDataChange(p0: DataSnapshot) {
patientDataItems.clear()
...
Upvotes: 0