Search code examples
firebaseandroid-recyclerviewandroid-livedataandroid-diffutilsandroid-listadapter

Firebase Realtime Database, ListAdapter, DiffUtil and ViewModel


I am trying to create a list view using Recycler View and display a list. Lets say what I am trying to display is like a typical chat screen - image, message, sender_name etc.

So all this data is stored in Firebase Realtime Database. I am also using ViewModel and would like to use DiffUtil for efficiency - since messages can be deleted, edited, starred, new ones added etc.. Due to DiffUtil, I am using a ListAdapter.

The issue I am facing is that the ListAdapter needs a List and I use a ChildEventListener.

How do I now observe changes from Firebase using LiveData and then update my list so that I can pass back into my DiffUtil? So if I add a new message, I'd like that to be added to my RecyclerView and I'd like to do that using DiffUtil since the list can also be updated.

What I found through research was that I might need to use Room for this purpose and observe the query for changes - so observe something like a getAllMessages() method which would return the complete list and then I can use that to pass into my DiffUtil. That sounds like an overkill to me - the implementation of Room.

Any pointers or suggestions on how I can achieve my need?

Here is the structure of my db: enter image description here


Solution

  • So I figured this out by doing the following in my ViewModel.

    private val _message = MutableLiveData<List<TextListModel>>()
    
    val message: LiveData<List<TextListModel>>
            get() = _message
    
    //...
    
    private val eventListener =
            object : ValueEventListener {
                override fun onCancelled(databaseError: DatabaseError) {
                    Timber.e("Error!! ${databaseError.toException()}")
                }
    
                override fun onDataChange(dataSnapshot: DataSnapshot) {
    
                    val listOfMessages : MutableList<TextListModel> = mutableListOf()
    
                    for(msg in dataSnapshot.children) {
                        val item = msg.getValue(TextListModel::class.java)
                        listOfMessages.add(item!!)
                    }
    
                    _message.value = listOfMessages
                }
            }
    

    In my fragment I observe message and perform adapter.submitList(newList) when there is an update.

    This downloading of data using ValueEventListener is concerning though since it pulls the data from under the node. I am checking on how to use ChildEventListener for my purposes.

    EDIT

    Seems like Value events don't download the full tree over! Value events work with the data in the local state and only downloads the delta.

    Some more information in this Youtube Video from 2016!