Hi, Habr! I present to your attention the translation of the article
ViewModels and LiveData: Patterns + AntiPatterns by Jose Alcérreca.
View and ViewModel
Distribution of responsibilities
Typical interaction of application objects, built with the help of Architectural Components:

')
Ideally, the ViewModel should not know anything about Android. This improves testability and modularity, reduces the number of memory leaks. The basic rule is that your ViewModel should not have android. * Imports (with the exception of android.arch. *). This also applies to Presenter.
ViewModel (and Presenter) don't need to know about Android framework classes
Conditional statements, loops, and general solutions must be carried out in ViewModel or other layers of the application, not in aktiviti or fragments. View is usually not subjected to unit-testing (except when Robolectric is used), therefore the fewer lines of code the better. View should only display data and send user actions to the ViewModel (or Presenter). This pattern is called Passive View.
Activations and fragments must contain a minimum of logic
Links to View in ViewModel
Scope ViewModels is different from activation or fragment scoping. In the meantime, as the ViewModel is initialized and running, the activation can go through several lifecycle states. The ViewModel may be unaware that the activites and fragments have been destroyed and created.
ViewModels is saved during configuration changes:

Transferring a link to a View (activation or fragment) in the ViewModel is a serious risk. Suppose the ViewModel requested data from the network, and they will come later. At this point, the link to the View may be destroyed or the activation may no longer be displayed - this will lead to a memory leak, and possibly to the crash of the application.
Avoid references to View in ViewModels.
The recommended way to communicate between the ViewModel and View is to use the observer pattern, using LiveData or observable from other libraries.
Observer Pattern (“Observer” design pattern)

A convenient way to design a presentation layer in Android is when the View (activation or fragment) watches (subscribes to changes in) the ViewModel. Since ViewModel does not know anything about Android, she also does not know how often Android kills View. This approach has several advantages:
- The ViewModel is saved when the configuration changes, so there is no need to re-request external data sources (for example, a database or network storage) when the device rotates.
- When any lengthy operation ends, the observable in the ViewModel is updated. It does not matter whether the data were monitored or not. NPE will not occur even when attempting to update a nonexistent View.
- ViewModel do not contain references to the View, which reduces the risk of memory leaks.
Typical subscriptions from an activation or a fragment:
private void subscribeToModel() {
Instead of sending data to the UI, let the UI monitor the changes in the data.
Fat ViewModel
Sharing responsibilities is always a good idea. If your ViewModel contains too much code, or has too many responsibilities, consider what you should possibly do:
- Move part of the logic to the Presenter, with the same scope as the ViewModel. That he will communicate with other parts of the application and update LiveData in the ViewModel.
- Add a Domain layer and adapt the application to the Net Architecture. This will facilitate testing and code support. It also usually leads to the fact that most of the logic is not executed in the main thread. An example of Pure Architecture is available in Architecture Blueprints .
Distribute responsibility, add a domain layer if required.
Use repository for data
As seen in
the application architecture guides , most applications have multiple data sources. Such as:
- Remote: network or cloud
- Local: database or file
- Cache
Creating an in-app data layer that knows nothing about the presentation layer is a good idea. Cache and database synchronization algorithms are not trivial. Therefore, it is recommended to create a repository class that will serve as the only entry point to combat this complexity.
If you have several data models and they are quite complex - it makes sense to add several repositories.
Add the data repository as the single entry point for the data.
Data State Processing
Present the following: You are subscribed to the LiveData updates provided by the ViewModel, which contains a list to display. How can View distinguish downloaded data from a network error or an empty list?
You can provide access to LiveData through ViewModel. For example, MyDataState may contain information about whether the data is loading correctly, whether it is finally loaded, or the download was interrupted.

You can wrap the data in a class that contains states and other metadata (for example, an error message). See the Resource class in the provided examples.
Expose information about the state of the data using a wrapper or other LiveData.
Keeping the activation state
The activation state is information that you will need to re-create on the screen if the activation was destroyed, or the process containing it was killed. Screen rotation is the most obvious case and this issue is closed by the ViewModel. The state is stored in the ViewModel in complete security.
However, restoring the state may be necessary in other scenarios in which the ViewModel was also destroyed: when the operating system resources run out and it kills the application process.
To efficiently save and restore the state of the UI, use the combination of data storage, onSaveInstanceState () and ViewModel.
For example, see:
ViewModels: Persistence, onSaveInstanceState (), Restoring UI State and Loaders EventsDevelopments
An event is something that happened once. ViewModel provides data access, but what about events? For example, navigation events or display of messages in Snackbar are actions that are executed only once.
The concept of the Event does not fit the way LiveData stores and recreates data. Imagine a ViewModel with this field:
LiveData<String> snackbarMessage = new MutableLiveData<>();
Activation subscribes to changes to this ViewModel, and when the ViewModel finishes the operation, a message should appear:
snackbarMessage.setValue(" !");
Activation gets the value and shows Snackbar. It seems everything works.
In spite of this, if the user turns off the phone, a new activation will be created, which will also subscribe to the ViewModel changes. When a subscription to the changes in LiveData occurs, the activation will immediately receive the old value and the message will be displayed again!
In order to solve this problem in one of our examples we created the class
SingleLiveEvent (the class is inherited from LiveData). It sends only those updates that occurred after the subscription to the changes. Also note that the class supports only one subscriber.
For events such as showing messages in Snackbar or navigating, use an observable like SingleLiveEvent.
Memory Leaks in ViewModels
The paradigm of reactive programming works great in Android, because provides a convenient connection between the UI and other layers of the application architecture. LiveData is a key component of this structure, so usually your activites and snippets will be subscribed to changes to LiveData instances.
How ViewModels will communicate with other components of the application is up to you, but beware of memory leaks and border conditions. In the diagram below, the Presentation layer uses the observer pattern and the Data layer, which receives callbacks.
Observer pattern in UI and callbacks in the Data layer:

If the user exits the application, the ViewModel is no longer observed by anyone. If the repository is implemented as a singleton or in some other way tied to the application's scopes, it
will not be destroyed until the application process is killed . This will happen only when the system needs resources or the user manually kills the application. If the repository refers to the callback in the ViewModel, a memory leak will be created.
Activity finished, but ViewModel continues to exist:

This leakage is not so important if the ViewModel is lightweight or the operation is guaranteed to complete within a short amount of time. Ideally, ViewModels should be freed in all cases where the View is missing and they are being watched:

This can be achieved in many ways:
- With ViewModel.onCleared () you can tell the repository that it should reset the callback to the ViewModel.
- You can use WeakReference or Event Bus in the repository (using both of them may be incorrect and even considered harmful).
- Use LiveData for communication between the repository and ViewModel as well as using it for communication between View and ViewModel.
Consider edge cases, memory leaks, and how long operations can affect the instances in your architecture.
Do not place logic in the ViewModel that is critical for maintaining the purity of the architecture or if it is associated with data. Each call made from the ViewModel may be the last.
LiveData in repositories
To avoid leaks in the ViewModel and callback hell, repositories can be observed as follows:

When the ViewModel is cleared or when the view's life cycle has stopped, the subscription is cleared:

This method has one subtlety: how to subscribe to the repository from ViewModel, if you do not have access to LifecycleOwner? With the help of
Transformations . Transformations.switchMap allows you to create LiveData that responds to changes in other LiveData instances. Due to this, information is transmitted through observer of the liquid cycle along the chain:
LiveData<Repo> repo = Transformations.switchMap(repoIdLiveData, repoId -> { if (repoId.isEmpty()) { return AbsentLiveData.create(); } return repository.loadRepo(repoId); } );
Transformation Example [
link ]
In this example, when the trigger receives an update, the function is executed and the result is cascaded. Activiti watches the repository and the same LifecycleOwner will be used to call repository.loadRepo (id).
Every time you think you need a Lifecycle object inside the ViewModel, using Transformation will most likely help to avoid this and solve the problem.
Inheriting from LiveData
The most common use of LiveData is to use the MutableLiveData in ViewModel to represent them as LiveData in order to make them immutable for observers.
If you need more functionality, inheriting from LiveData will let you know if there are active observers. For example, this can be useful if you want to start listening to the location service or senosory of the device.
public class MyLiveData extends LiveData<MyData> { public MyLiveData(Context context) {
When not to inherit from LiveData
You can also use onActive () to start some service that loads data, but if you don’t have a good reason for this, you don’t have to wait until LiveData begins to be observed. The most common patterns:
Add the start () method to the ViewModel and call it as soon as possible [see
Blueprints example]
Assign a field that stops loading [see
GithubBrowserExample example].
Normally, inheritance from LiveData does not occur. Let the activation or snippet tell ViewModel when to start loading data.
Original article