
Android — RecyclerView using MVVM and DataBinding
A few days ago I wrote an article on how to implement form validation using MVVM and data-binding. The idea here wasn’t to teach form validation, MVVM or data-binding, but rather to give a comprehensive example of how MVVM with data-binding can be used for complex requirements. I got a lot of questions from people about how can we have separation of concerns between ViewModel, Model and UI in the case of something like a RecyclerView. The short answer is that it’s possible, though it requires some thinking ahead.
RecyclerView functionality
Like before, while I try to provide a list of techniques to use, it’s by no means a full list. The hope is to empower you to a point where you can fit in whatever requirements you have while respecting the MVVM pattern.
That being said, our app will sport the following features:
- When the app loads, a list of dog breeds will be loaded from an API call.
- When the list is displayed we will request images for each breed as it’s loaded by the RecyclerView.
- When a dog breed is clicked, we propagate the click to the activity.
Show me the code
In that code repo, you’ll find 2 implementations, each slightly different. The master
branch has an implementation that aims to have to have all functionality exposed to the Views through the ViewModel while method_alt
has an alternate implementation that in some senses simplifies the code, but the downside is that the View is aware of the Model object backing it making the code more tightly coupled and IMHO contrary to the MVVM design.
Code explained
Model explained [code]
The main thing to note here is that the fetch functionality is encapsulated in the model. When we want to fetch a list of dog breeds, the model object DogBreeds
has a fetch method. When we want to fetch the images for a dog breed, the DogBreed
(singular, spelt without an “s”) has a fetch method to fetch the list of dog images.
In the instance of DogBreeds
, the model object sets the list of breeds within itself, however the Activity
is the one listening for a change to the list of dog breeds. The idea here is that the Model
will not automatically tell the RecyclerView
adapter to update itself. Instead it, a View
, such as an Activity
or Fragment
attaches an observer to the dataset and tells the ViewModel
to update the adapter if needed. This is important, because we need to have a degree of separation between the Model
and the View
and if the Model
directly updates the View
, then a dependency on that particular View
is created within the Model
.
When a DogBreed
is displayed by the RecyclerView
, the RecyclerView
in method_alt
calls the fetch method for the images directly, in master
, the RecyclerView
adapter goes through the ViewModel
to tell the DogBreed
object to fetch images. I like the approach of going through the ViewModel
because under MVVM
, the ViewModel
is meant to expose functionality in the Model
to the View
. Hence, this feels more pure to me. When an the list of images is fetched, the ViewModel stores it in an Observable map. Then the layout fetches the images from this map through data-binding. I also like this approach because the image URL’s are retained through orientation changes (thanks to the Android LifeCycle components handling this automatically) and so there is no need to fetch the images again.
CustomViewBindings explained [code]
The code here is designed to allow you to bind a RecyclerView
to an adapter without having to hold a hard reference to RecyclerView
in the ViewModel
. The main reason you don’t want to do this is that while the Adapters functionality may be reusable, you may choose to use it with a different RecyclerView
so you want to move this code out from your ViewModel
. You can see in the layouts for the RecyclerView
and the list items how these are used.
ViewModel explained [code]
As I have mentioned repeatedly, the ViewModel’s job is to expose functionality to the View and maintain some state for the View. So what you see here are the various methods that are called either from the Activity
/Fragment
or from the layout
/data-binding
to get or set data.
Activity explained [code]
The main take away here is that the Activity triggers the ViewModel to fetch the list of DogBreeds and then observers for a change to the list of dog breeds. When it receives a change to the list, it asks the ViewModel to update the adapter with the new dog breeds. This is important because the Activity is the View. It knows the data it needs to display and should be listening for when that data changes or becomes available.
RecyclerView adapter [code]
This code is fairly stock standard. The only thing out of the ordinary is that the Adapter is not directly holding a reference to the data it is displaying. Instead it knows of the ViewModel and passes this down to the data-binding where the layout requests the correct object based on its index. This is slightly different from the method_alt
implementation where the DogBreed
object is directly accessed by the adapter and added to the data-binding
.
Finally
Hopefully there is enough there to help you use a RecyclerView with Data Binding and the MVVM pattern no matter what your requirements. One thing is for sure in order to build great Android apps, read more of my articles.