Hello, guys, I had so much fun writing my previous article about LiveData that I started to think about the next one right away, the obvious choice for the topic was the next component of the Android Architecture Components framework so I thought about making it a series where we will cover all of them, so this is the second part of the series where we will talk about ViewModel
ViewModel is a class that has been designed with the main goal of storing data that is related to the UI in a lifecycle aware manner, it’s implemented in such a way that it outlives any configuration change, such as device rotation.
Why do we even need it?
Android Framework handles the lifecycle of Activities and Fragments, which from now on we will refer to in-distinctively as the `UI Controller`, and it can decide to destroy and recreate them in response to events that are completely out of the developers control, any transient data is then lost. In some occasions this can lead to poor performance as any data that is lost in this way will need to be retrieved once again (think about having to retrieve a long list of users from the network every time the device is rotated). Of course, the framework provides the onSaveInstanceState() method to save data across instances of the UI Controller, but it has some limitations as it can only handle simple data that can be serialized and deserialized.
Another problem that arises from this paradigm is that usually the UI Controller gets more responsibilities than it ideally should, let’s say we got a fragment where we show some user data retrieved from the network, this MUST be retrieved in an asynchronous way and it’s not uncommon to see that the responsibility of making, handling and cleaning these calls lies in the UI Controller. This kind of approach should not be used as the UI controller should limit it’s responsibilities to show data, get inputs and maybe some interface with the framework, as when requesting permissions.
There must be a better way…
Android Architecture Components introduced a helper class for the UI Controller that is responsible of getting the data to show in the UI. ViewModel objects outlive the lifecycle of the UI Controllers and are retained during configuration changes, so they are are ready for the next instance of the UI controller, this is why they should be delegated any work consisting on getting data.
If the UI Controller is recreated it will receive the very same instance of the ViewModel bound to it’s scope. Let’s say we got an activity in which we retrieve a ViewModel instance, as long as the activity is not finished it will receive the same instance of the ViewModel every time it’s recreated. This is very important as ensures we can forget about having to retrieve the data every time the UI Controller is destroyed due to configuration changes. Once the UI controller is no longer used ( finished in the case of activities and detached in the case of fragments) the framework will call ViewModel’s onCleared() method, giving you the chance to perform any cleanup routine you need.
Let’s see a sample from the Android Docs, that’s is simple enough to illustrate how you would use ViewModel
It’s important to note here the call to the `of()` static method in the ViewModelProviders class, as you can see a reference to the Activity is passed, this is used to determine the scope of the ViewModel, ViewModelProviders also got an of(Fragment) method so you can get a ViewModel instance in any scenario.
ViewModel can contain any LifecycleObserver object, as LiveData, but it should never be bound to a specific instance of a UI Controller, as it can be a source of memory leaks. There are some cases in which you would need to get a Context to work with in the ViewModel, in these cases you should extend AndroidViewModel instead, it will receive an Application object in it’s constructor.
Sharing is not always easy
It’s a common scenario that two or more fragments need to communicate with each other sharing objects and depending one on another to do their work. Usually you would need to define some kind of interface with callbacks to let them know what it’s going on with each other, also the activity containing them would need to perform the “binding” between the fragments and ,as this was not enough, each of the fragments would need to handle the cases where the other have not yet been created or are not visible.
Let’s say that you got two fragments, FragmentA and FragmentB; in FragmentA you present a list of User and in FragmentB, once a user is selected, you show it’s details; instead of following the method described above you could use a ViewModel containing the selected User, but instead of binding it to one given Fragment you would bind it to the Activity instead, in this way both of the fragments will get the same instance!
Right away this method has several advantages over the tedious process described before:
1.The activity doesn’t need to know about the communication, this translate to less code to write and less sources of potential bugs
2. The fragments don’t know about each other, this means that at any time each of the them can be updated or even completely replaced independently and, as long they respect the contract to the ViewModel, they will continue to work fine
3. We don’t have to handle the cases in which any of the fragment is not yet created or visible.
As we can see using ViewModel simplifies a lot of the work that has to be done in a wide range of scenarios, and since it’s supported directly by the framework it’s worth to be included in all of your projects.