MVVM’s ViewModel implementation in Android application. Architecture Components’ ViewModel
What is ViewModel?
ViewModel – it is a model of the view. The purpose of the ViewModel is to apply any business logic to the Model before exposing it to the View for consumption. This way the View is free of business logic. Its only purpose is to apply UI logic related to user interactions. The ViewModel exposes the data to the View via Observables.
Why is it bad not to use ViewModel?
ViewModel is used to store UI related data and expose this data to the View via observables. It is a common mistake to store all the UI related data in the Activity or Fragment itself. However, the Android framework manages the lifecycle of these components and it may decide to destroy or re-create a UI controller due to user actions or device events which are out of your control. If this happens, all the information stored in the UI component is lost. You may persist some of the data in the onSaveInstanceState() method of an Activity and then restore it in the onCreate() method but this is used for only small amounts of data. We can’t persist ArrayLists of objects or other complex Java structures there. If all the data is lost we have nothing else to do except trying to restore it – making a new database call or sending a request to fetch the data again. However this is resource consuming operation and it should be avoided. The most common scenario for destruction of UI controller is the rotation of the screen. For example if we show a list of cryptocurrencies and their daily OHLCV prices (open, high, low, close, volume) in a ListView in an Activity, the data is fetched with a HTTP request and then saved to the database every time the Activity is created. It would be a bad experience if we lose this data due to orientation change. If we don’t persist it in a ViewModel we would need to do these operations again to restore the lost data. Now imagine the rotation happens at least 10 times for 10 seconds. This means 10 HTTP requests and 10 calls to the database. And this would definitely also lead to memory leaks too.
What is the solution?
The solution is to persist the once fetched data in the ViewModel because Android’s ViewModel component, part of the Architecture Components, outlives the specific instantiation of its lifecycle owner (an Activity or Fragment) and no matter how many rotations occur, the data is persisted in the ViewModel and is fetched only once. Each instance of the re-created Activity gets the same ViewModel instance. This is the reason why the ViewModel should never hold reference to the View. If the View is destroyed and the ViewModel holds a reference to it, memory leaks are likely to occur.
Lifecycle of the ViewModel
ViewModel stays in memory until the Lifecycle it’s scoped to goes away permanently. In the case of an Activity – when it is finished, and in the case of Fragment- when it is detached. In the illustration below are represented the states of the ViewModel. As it can be seen the ViewModel outlives its lifecycle owner – in this case an Activity. Although the Activity is destroyed and then re-created due to orientation changes, it still gets the same instance of the ViewModel. The ViewModel is destroyed after the Activity it is associated with calls its finish() method and the onDestroy() lifecycle callback is invoked. Then the ViewModel’s onCleared() method is called where you should clear the subscription to observed data to prevent a leak of the ViewModel.
In the next chapter we will go through the steps of creating a simple ViewModel and see the ViewModel in action.