MVVM Architecture for Custom Views on Android

Matthias Siegmund
3 min readMar 11, 2019

--

Nowadays applications are getting more and more complex. The more complex your app is the more important it is to ensure that you are writing stable, maintainable and testable code. To achieve that we make use of software design patterns such as Model-View-ViewModel.

This is a very common practice by now for Fragments and Activities. Google also offers a lot with the Architecture Components that were introduced at Google I/O 2017 to help us applying MVVM to Fragments or Activities. But what happens if you want to create a self-contained Custom View that can be used at different parts of your app?

Custom Views offer a great way to encapsulate certain functionalities. This helps to reduce the size and complexity of its parent which results in less responsibilities and less room for errors.

However imagine you want to have the same Custom View in different Activities that do not share the same ViewModel. If your Custom Views logic relies on the ViewModel of the Fragment or Activity it lives in it becomes impossible without duplicating the code from the ViewModel.

Since the Architecture Components don’t support Custom Views we have to come up with out own solution to apply MVVM to Custom Views:

To get a clearer picture of how to implement this properly let’s take a look at the definition of our MvvmCustomView.

This interface defines the basics we need to turn a Custom View into a self-contained component starting with the ViewModel. The ViewModel will be the place where we have our business logic and where we expose our LiveData that represents a certain state of the UI. To observe the ViewModels LiveData we also need a LifecycleOwner. Therefore we define a method that will have the LifecycleOwner passed into. Under the hood we obtain it through the contextof the Custom View. Obviously this requires the parent to implement LifecycleOwner. To protect ourselves from using the MvvmCustomView outside of the context of a LifecycleOwner we throw a LifecycleOwnerNotFoundException in case the context cannot be casted. Also since we cannot use the ViewModel class from the Architecture Components we have to take care of the state recreation ourself. That will be handled by the Custom View itself.

A possible implementation of this interface could look like this:

To avoid implementing the same stuff — like state recreation — over and over again for each Custom View we can create abstract classes that handle the boiler plate:

The MvvmCustomViewState is basically nothing else then e.g. a data class that implements Parcelable to save and restore all necessary information:

A possible implementation of this interface could look like this:

You might have noticed that we need something else here in order to make the saving and restoring of the state work: MvvmCustomViewStateWrapper. This is basically — like the name implies — just a wrapper for the MvvmCustomViewState as well as the saved instance state of the view.

The last piece in our puzzle is the MvvmCustomViewModel:

This interface only defines that we are going to have a MvvmCustomViewState that we will need for restoring the state of the ViewModel on our own.

A possible implementation of this interface could look like this:

We are basically set now! All we have to do now is to make sure that each instance of our Custom View has a different id in the layout to ensure that the state recreation is working.

Summary:

MVVM does not only make sense for Activities and Fragments but for Custom Views as well. We cannot make use of the full potential of the Architecture Components though. Therefore we implement it on our own and end up with a unit-testable and self-contained component that can be reused all over the application without duplicating any business logic that is bound to the Custom View.

Below, you can find a link to a GitHub Repository with a simple example of a Custom View utilizing MVVM.

--

--