Using Android Jetpack ViewModel
By: Kayvan Kaseb
Tags: Android Apps, Jetpack, Android, Android App Development, Viewmodel

Photo is provided by https://unsplash.com/photos/ejvOgTb8XmA

Basically, ViewModel is a part of the Android Architecture Components. One of the main goals of ViewModel object is serving data to the Android UI components such as activities or fragments, and separating the data processing logic from the UI. Another aspect of ViewModel is managing UI-related data in a lifecycle conscious way. This feature allows data to survive configuration changes like screen rotations. This essay aims to discuss ViewModel concepts, and also the required steps to implement ViewModel in Android applications.

Overview and Introduction

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

Basically, ViewModels are objects that support data for UI components, and survive configuration changes. In fact, rotating your mobile phone is considered a configuration change. Configuration changes cause your whole activity to get recreated. If you do not properly save and restore data from the destroyed activity, you will lose that data. In addition, you will face some UI bugs or crashes. Thus, instead of storing all of your UI data in your activity, you should put it in the ViewModel. In this case, this helps with configuration changes; however, it is also a best practice for software design. In other words, one common pitfall when developing for Android is putting a lot of variables, logic, and data into your activities and fragments. This creates a large unmaintainable classes, and breaks the rule of single responsibility principle in SOLID principles. As a result, you can be able to use ViewModel to easily divide out that responsibility. The ViewModel will be responsible for holding all of the data that you want to show in your UI, and then the activity is only responsible for knowing how to show that data to the screen for receiving user interactions, but not for processing those data. Another significant point is that if your Android app loads and stores data, you can create a Repository class as explained in the Guide to App Architecture document by Google because your ViewModel should not be faced with excessive responsibilities.

Using Repository class in your app architecture, the picture is provided by Google documents

In other words, UI controllers such as activities and fragments are mainly intended to display UI data, react to user interactions, or handle OS communication like permission requests. Additionally, UI controllers can be responsible for loading data from a database or network connection. In fact, setting excessive responsibility to UI controllers can result in a single class, which tries to manage all of an app’s tasks by itself, instead of delegating work to other classes. Thus, setting excessive responsibility to the UI controllers in this way can make testing process much more difficult.

ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment. It also handles the communication of the Activity / Fragment with the rest of the application (e.g. calling the business logic classes).

Another important problem is that UI controllers (activities and fragments) frequently need to make asynchronous calls that may take some time to return the result. So, the UI controller needs to handle these calls, and make sure the system cleans them up after destroying to avoid some potential memory leaks. It is clear that this issue needs a lot of maintenance because an object is re-created for a configuration change, and this leads to waste of resources due to this repeated processes.

ViewModel’s only responsibility is to manage the data for the UI. It should never access your view hierarchy or hold a reference back to the Activity or the Fragment.

Implementing ViewModel

Create a subclass of ViewModel

To create a ViewModel, you will need to extend the ViewModel class, and then you can put your UI-related instance variables that were previously in your activity into your ViewModel. For example:

class UserViewModel: ViewModel() { val user = User(name = "", address = "") }

2. Set up ViewModel Provider in your activity’s onCreate

Then, in your activity’s onCreate, you get the ViewModel from a framework utility class that is called ViewModel Provider. Notice the ViewModel Provider takes an activity instance. This is the mechanism that allows you to rotate the device, get a technically new activity instance, but always make sure that activity instance is connected with the same ViewModel.

override fun onCreate(savedInstanceState: Bundle?) {



val userViewModel =

ViewModelProviders.of(this).get(UserViewModel)::class.java)

userViewModel.user.name = "John"



}

By using the ViewModel instance, you can be able to use Getters and Setters to access UI data from your activity. If you want to customize the default constructor, which currently no parameters, you can use a ViewModel Factory for implementing a custom constructor.

3. Use LiveData and Data Binding with your ViewModel

Currently, this is the simplest form of a ViewModel, but the ViewModel class is also designed to work appropriately with LiveData and Data Binding libraries. By using all of these approaches, you can create a reactive UI for your Android app, which indicates that your UI will automatically updates whenever the data changes.

The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.

ViewModel + LiveData + Data Binding = Reactive UI

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

This assumes all of your data in your ViewModel, which you plan to represent on screen is packed in LiveData as follows:

class UserViewModel: ViewModel() { private val _user MutableLiveData<User>() val user : LiveData<User>

get() = _user



}

Then, you should set up Data Binding. For instance, the XML with the Data Binding layout tag and variable tag for your ViewModel are as below:

<layout>

<data>

<variable>

name="viewmodel"

type="android.example.com.UserViewModel"/>

</data>

<.../>

</layout>

After completing this step, you should add these lines of codes to your activity’s onCreate as below:

override fun onCreate(savedInstanceState: Bundle?) {



// Rest of the onCreate method...



val binding = ActivityMainBinding.inflate(layoutInflater)

binding.viewmodel = userViewModel

binding.setLifecycleOwner(this)

setContentView(binding.root)



}

In above code setLifecycleOwner() method allows the binding to observe your LiveData objects in the ViewModel, and this helps the binding update whenever the LiveData changes.

The lifecycle of a ViewModel

In the below diagram, you can be able to see the lifecycle of an Activity, which faces a rotation. The lifetime of the ViewModel is displayed next to the associated Activity lifecycle. As a matter of fact, ViewModel can be easily used with both Fragments and Activities. The ViewModel exists from when you request a ViewModel firstly (in activity’s onCreate) until the activity is finished and destroyed. Thus, onCreate() could be called several times during the life of an Activity.

The lifecycle of a ViewModel for an activity, picture is provided by Google documents

Differences between ViewModel and onSaveInstanceState

Fundamentally, although ViewModel is designed to be applied in addition to onSaveInstanceState as an another option, there are some differences can be mentioned clearly. ViewModels do not survive process shutdown because of resource restrictions, but onSaveInstance bundles do this task. ViewModel is a great choice for storing huge amounts of data; whereas, onSaveInstanceState bundles is not an appropriate option for that purpose. ViewModels are utilized to store as much UI data as possible. Therefore, that data does not need to be reloaded or regenerated during a configuration changes. onSaveInstanceState, on the other hand, should store the smallest amount of data needed to restore the UI state if the process is shut down by the framework. For instance, you might store all of the user’s data within the ViewModel while just store the user’s database ID in onSaveInstanceState.

ViewModel and Context

ViewModels should not hold a reference to Activities, Fragments, or Contexts. Furthermore, ViewModels should not include references to UI controllers like Views since this will create an indirect reference to a Context. When you rotate the screen that activity is destroyed, you have a ViewModel that holds a reference to a destroyed activity, and this is a memory leak. So, if you need to use contexts, you must use application context (AndroidViewModel subclass).

In conclusion

As a matter of fact, ViewModel is a class that is responsible for preparing and handling the data for an Activity or a Fragment. Also, it manages the communication of the Activity and Fragment with the rest of the application like calling the business logic classes. This essay considered ViewModel concepts, and also the required steps to implement ViewModel in Android applications.