Need help in implementing ViewModel class with Cloud Firestore backend

Viewed 1139

I am developing an application that fetches some documents from the Cloud Firestore and shows the contents of the documents in a RecyclerView. I want to follow the principle of separation of concern, and therefore using the MVVM architecture to build the app. I have implemented a Data class model and the adapter for the RecyclerView using the FirestoreRecyclerAdapter.

I have already worked on a guided project which used MVVM architecture with LiveData and Room. In that project, the adapter implemented had an ArrayList which held all the data which was in turn used to populate the RecyclerView.

viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(NoteViewModel::class.java)
viewModel.allNotes.observe(this, { list->list?.let{
            adapter.updateList(it)}
        })

Similarly, I have worked on a project which used Firestore but did not employ the MVVM architecture. In the latter one, the RecyclerView got inflated with data without passing any data to any collection whatsoever. It did not even use LiveData but the changes in Firestore were reflected instantly (which I believe is one of many benefits of Cloud Firestore).

postDao = PostDao()
val postcollection = postDao.postCollections
val query = postcollection.orderBy("createdAt", Query.Direction.DESCENDING)
val recyclerviewOptions = FirestoreRecyclerOptions.Builder<Post>().setQuery(query, Post::class.java).build()


adapter = PostAdapter(recyclerviewOptions)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

As in the code above, simply passing the collection to the adapter inflated the RecyclerView.

But now in this project where I want to implement the architecture, I am having an issue with the ViewModel class. What should it contain? And how do I use the FirestoreRecyclerOptions with the ViewModel? Do I need a collection (like a List or an ArrayList) to wrap the data from the DAO in the LiveData? Or do I need the LiveData at all? The reference docs state that I should use MutableLiveData on some object or collection, and then I should have a method to update the list every time the data changes. There is also an observer method that is implemented. But I don't see any explanation about Firestore or how the FirestoreRecyclerAdapter is even working. What I need is what do I need to implement in the ViewModel class in respect to MutableLiveData on collections from the database and update functions in the FirestoreRecyclerAdapter in the context of Cloud Firestore.

1 Answers

Similarly, I have worked on a project which used Firestore but did not employ the MVVM architecture. In the latter one, the RecyclerView got inflated with data without passing the data to any collection whatsoever.

That's was happening because you were using Firebase-UI library for Android, meaning that all the heavy work was done behind the scenes by this library. What you had to do, is to create only a "FirestoreRecyclerOptions" object, pass it to the adapter, and that's pretty much all of it.

It did not even use LiveData but the changes in Firestore were reflected instantly (which I believe is one of many benefits of Cloud Firestore).

There is no need for any LiveData object, as all the work for getting the data in real-time is accomplished by the library. Yes, Cloud Firestore it's a real-time database, but you can achieve the same behavior also without the use of a library. You can use Cloud Firestore client SDK, but all that mechanism should be implemented by yourself. So that real-time mechanism was actually provided by the Firebase-UI library and not by the Cloud Firestore database itself. To listen for changes in real-time, please check the official documentation regarding, Get real-time updates with Cloud Firestore:

You can listen to a document with the onSnapshot() method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot.

Furthermore,

But now in this project where I want to implement the architecture, I am having an issue with the ViewModel class.

As I understand, you want to implement the MVVM architecture pattern in your project. In this case, you'll have to write code for that, meaning that you should separate the concerns, by creating a Model, a View (activity or fragment), and a ViewModel separately.

And how do I use the FirestoreRecyclerOptions with the ViewModel?

You cannot mix the Firebase-UI library with the MVVM architecture pattern, as none of them is compatible with each other. It's one, or the other.

Or do I need the LiveData at all?

Yes, you need a LiveData object that can be observed in the ViewModel class directly from the activity/fragment class.

The reference docs state that I should use MutableLiveData on some object or collection, and then I should have a method to update the list every time the data changes. There is also an observer method that is implemented.

Yes, that's how MVVM works.

But I don't see any explanation about Firestore or how the FirestoreRecyclerAdapter is even working.

You cannot see any use of "FirestoreRecyclerAdapter" because you cannot use this kind of object in an MVVM architecture pattern. This is happening because when creating a new instance of the "FirestoreRecyclerAdapter" class, you need a "FirestoreRecyclerOptions" object that should be passed to its constructor. This means that this kind of object is tight to the activity/fragment. So if you are using this kind of object in the activity class, you break the MVVM architecture pattern principle, which says that the activity should know nothing about its data source.

What I need is what do I need to implement in the ViewModel class in respect to MutableLiveData on collections from the database and update functions in the FirestoreRecyclerAdapter in the context of Cloud Firestore.

As explained above you cannot do that, with respect to the MVVM architecture pattern. It's one or the other. You can use the Firebase-UI library with all the benefits it comes with, or you can use the MVVM architecture pattern.

You might wonder, which is better?

It depends on what you consider more important, the benefits of the library or the architecture pattern. If you are asking me, I prefer to have a simplified code and use the library.

If you want a simpler code, then you can use Dependency injection with Hilt, and inject an instance of your "FirestoreRecyclerOptions" class, directly into your activity/fragment class.

Please see below one of my repositories, as an example of getting data from Firestore using MVVM:

Related