The problem that ViewModel solves

Let me start with the truth – “ViewModel is a choice , not a compulsion” .

You can use any architecture that works for you , and probably you have one ( if you don’t then please have one as bloating your UI components is the worst practice ) . And chances are , you have experienced all the different , well known issues related to android lifecycle events and the state of your app’s UI . So you may have found the solutions to all your problems and you are living happily now , but still give ViewModels a try as it is preferred by Google and you may realize that it solves the problems in a more elegant way .

In this tutorial we are going to create a simple app to display the list of apps installed on a device . And we’ll start with the problem that ViewModel solves .

The following code represents the main fragment of our app (responsible for displaying the list of apps) , we have not used any architecture . We have a method getList() get retrieve the list of installed apps and then we pass it to our AppListAdapter to display in a RecyclerView . 

And our app looks like the one shown below ,  we also have a filter option to display only the system apps or the downloaded apps .

The problem : Our list gets reloaded on configuration change

Now let us experience the problem with data persistence on configuration change . 

  • Let us filter the list to display only the downloaded apps . 
  • Change the orientation of the device 
  • Now we no more have the filtered list of downloaded app , instead the default list of all apps gets loaded .

You can experiment with different filters and different types of configuration changes yourselves .  You can know more about the different types of configuration changes here .

The video below demonstrates this behavior for some of the configuration changes . 

The reason of such behavior is that our activity gets destroyed and recreated on configuration changes . 

So for example if we have filtered the list and now 

filterKeyNew = “downloaded” 

After configuration change –

filterKeyNew =”all”and  

items: ArrayList<PackageInfo> = ArrayList<PackageInfo>()

Solving the problem with onSavedInstanceState :  Yes we can save the filterKey in onSaveInstanceState and retrieve it in from the savedInstaceState bundle in onCreate . And then the getList() method with get the list of apps using the this filterKey . 

Seems like our problem has been solved right? But imagine, instead of loading the list of apps installed in the device we are making some api requests to a remote server .  And as we are only storing the filterKey , every time we rotate the screen ( or any other type of configuration change occurs) a new api request is made to the server which may keep the user waiting for the data . And this may lead to very bad user experience .

But can’t we save the complete filtered list of apps ( items in our case) in onSaveInstanceState() ?  Well we can , but we shouldn’t ! as this may lead to a TransactionTooLargeException  .  onSaveInstanceState()  is meant to store small amount of data ( only for primitive types and simple, small objects such as String ) .

Another problem : Violation of the principle “Separation of concerns”

Do we need an Activity to write the code to add two numbers ? Or do we need a Fragment to retrieve the list of apps ? 

Definitely not . We need these UI components to interact with the users and the operation system . The code for the calculator or to retrieve list of apps can be written in any independent class . 

And we don’t even have any control over these classes , they are managed by the OS and can get killed anytime .

How a ViewModel can help us here ?

Now as we know that what we are doing is a bad practice , we have to find a way to separate the UI and the business logic . There are many different approaches  to handle this but we are concerned about ViewModels here . 

An instance of a ViewModel can hold data in lifecycle conscious way . On configuration change an activity or fragment get destroyed and recreated . But ViewModels are retained and the same instance of the ViewModel is provided to the new instance of the Activity/Fragment . 

Hence if we keep our filterKey (String) and the item (list of apps) in a ViewModel we won’t need to reload the list of apps again after configuration change .  

And by moving getList(filter: String) from AppsFragment to a ViewModel we will relieve our AppsFragment from the additional tasks which it shouldn’t be held responsible for .

Leave a Reply

Your email address will not be published. Required fields are marked *