MVVM is an Android architecture that combines Data Binding with some lifecycle components, such as LiveData and ViewModel. Details can be found
Google official sample library.

The View and ViewModels

In theory, the ViewModel doesn’t need to know anything about Android. This provides testability, memory leak prevention, and modularity benefits. One basic rule is to make sure that there are no android.* class imports in your ViewModels class (except Android.arch.*). It’s the same with presenters.

Don’t let ViewModels (and Presenters) know anything about the Android framework classes.

Conditional statements, loops, and general decisions should be made in the ViewModels or other layers of your app, not in activities or fragments. Views are usually not unit tested (unless you use Robolectric), so the less code the better. The View should only know how to present data and send user events to the ViewModel (or Presenter). This is called passive view mode.


Keep the logic of minimization in Activities and Fragments

Reference the View in ViewModels

ViewModels have a different scope than Activities or Fragments. While a ViewModel is alive and running, an Activity can be in any state of its life cycle. Activities and Fragments can be destroyed and created again without the ViewModel knowing it.

ViewModels still exists when configuration changes

Passing a reference to a View (Activity or Fragment) into the ViewModel is a serious risk. Suppose network data is requested in the ViewModel, and the data is returned some time later. At this point, the View’s reference may be reclaimed or the old Activity may no longer be visible, causing a memory leak or even a crash.

Avoid referencing Views in ViewModels

The way to communicate recommendations in ViewModels and Views is in observer mode, using the observable mode provided by LiveData or other libraries.

Observer model


Using observer mode, it is very convenient to have a View (Activity or Fragment) observe (subscribe to changes) the ViewModel in the Android display layer. Because the ViewModel doesn’t need to know the Android content, it doesn’t know how frequently Android kills the View. The benefits are:

  1. The ViewModels remains when the configuration changes, so there is no need to query the internal data (database or network) again when the screen is rotated.
  2. When a long operation ends, the observable part of the ViewModel is updated. No null-pointer exceptions occur when attempting to update a View that does not exist, regardless of whether the data is observed or not.
  3. ViewModels does not reference views, so it reduces the risk of memory leaks.
private void subscribeToModel() { // Observe product data viewModel.getObservableProduct().observe(this, new Observer<Product>() { @Override public void onChanged(@Nullable Product product) { mTitle.setText(product.title); }}); }Copy the code


Register a data push in the UI and let the UI watch it change.

Bloated ViewModels

If you have too much code or too many responsibilities in your ViewModel, consider:

  • Move some logic to presenter, which has the same scope as ViewModel. It can communicate with other parts of your app and update the LiveData holder in the ViewModel.
  • Adding a domain layer and adopting a clean architecture facilitates testing and maintenance, as well as quick off-main threads. There is an example of a clean architecture in the architecture blueprint.


Decentralize responsibilities and add domain layers if necessary.

Using a data warehouse

In the App Architecture Guide, you can see that most apps have multiple sources of data, such as:

  1. Remote: Network or cloud
  2. Local: database or file
  3. Memory cache

It’s a good idea to have a data layer in your application that the presentation layer doesn’t notice at all. Algorithms that preserve caches and synchronize databases and networks are irrelevant. Having a fully isolated warehouse class as a single point of entry to handle these complexities is highly recommended.

If you have multiple and different data models, consider adding multiple repositories.


Add a data warehouse as a single point of access to the data.

Processing data state

Consider this scenario: You are looking at LiveData exposed in the ViewModel, which contains a list of items to display. So how does the view present these changes when data is loaded, network errors, or empty lists?

  • You can expose a LiveData

    in the ViewModel. For example, MyDataState should contain information about whether that data is being loaded, or whether loading succeeded or failed.

You can wrap data in a class that holds status or other metadata, such as an error message. Take a look at the Resource class in our sample.


Use some wrapper class or another LiveData to expose information about your data.

Save the Activity state

The Activity state is the information that you need to resume the screen when an Activity disappears (meaning it was recycled or the process was killed). The rotating screen is the most obvious example, but we have the ViewModel. State is safe in the ViewModel.

However, in some scenarios, when the ViewModel also disappears, you may also need to restore the state. For example, when the operating system is running low on resources, it can kill your processes.

To save and restore UI state efficiently, you need to combine persistence, onSaveInstanceState(), and ViewModels.

See examples: ViewModels: Persist, onSaveInstanceState(), restore UI state and loader

The event

An event is an action that is sent once. ViewModels expose data, but what is an event? For example, navigating an event or displaying a Snackbar message are actions that should only be performed once.

The concept of events does not do a good job of showing how LiveData stores and recovers data. Take a look at the following ViewModel:

LiveData<String> snackbarMessage = new MutableLiveData<>();
Copy the code

An Activity starts observing the data, and the ViewModel needs to update the message after it completes an operation:

snackbarMessage.setValue("Item saved!" );Copy the code

The Activity receives this message and displays it in the Snackbar. There’s nothing wrong with that, obviously.

However, if the user rotates the phone, a new Activity is created and observed. When the LiveData observation occurs, the Activity immediately receives the old value, and the message is displayed again!

We extended LiveData and created a class called SingleLiveEvent as a solution to the previous problem. It only sends updates that occur after a subscription. Note that it supports only one observer.


Use observable behavior for events such as navigation or Snackbar messages
SingleLiveEvent.

Let the cat out of the ViewModels

The reactive paradigm works well in Android because it allows easy connections between the UI and other layers of the application. LiveData is a key component of this structure, so it is common for your Activities and Fragments to observe an instance of LiveData.

How ViewModels communicate with other components is up to you, but be aware of leaks and boundary conditions. The demo layer uses observer mode and the data layer uses callbacks:


If the user exits the application, the View disappears, so the ViewModel is no longer observed. If the repository is a singleton, or application-wide, then the repository will not be recycled until the process is killed. This only happens when the operating system needs resources or the user manually kills the application. If the repository keeps a reference to the callback in the ViewModel, the ViewModel is temporarily compromised.


This leak is fine if the ViewModel survives or the assigned operation completes quickly. However, not all the time. Ideally, ViewModels should be recycled when no Views are observed:


You can do this with the following options:

  • Using viewModel.oncleared () you can tell the repository to discard the ViewModel callback.
  • In the repository you can use weak references or EventBus (both of which can be easily abused or even harmful)


Consider how boundary conditions, leaks, and long-running operations affect instances in your architecture.







Do not store cleanup state or related key logic in the ViewModel. Any call you make from the ViewModel is probably your last.

LiveData in the warehouse

To avoid the leak and callback hell of ViewModels, the repository can observe:


The subscription is also cleared when the ViewModel is cleared or when the View’s life cycle ends:


There’s a catch if you use this approach: if you don’t visit LifecycleOwner, how do you subscribe to the ViewModel from the repository? A quick way to do this is to make yourself look quick. Transformations. SwitchMap allows you to create a new LiveData, can respond to other LiveData instance. It also allows you to carry the lifecycle information of the observer through the chain:

LiveData<Repo> repo = Transformations.switchMap(repoIdLiveData, repoId -> { if (repoId.isEmpty()) { return AbsentLiveData.create(); } return repository.loadRepo(repoId); });Copy the code

In this example, when an update is triggered, the function is called and the results are distributed downwards. An Activity can observe the repo and the same LifecycleOwner will be used with a call to repository.loadrepo (ID).

✅ whenever you consider in
ViewModel
The use of
The life cycle
Object,TransformationCould be a solution.

Inheritance LiveData

The most common use case for LiveData is to use MutableLiveData in ViewModels and expose them as LiveData, making them immutable to other observers.

If you need more functionality, inheriting LiveData lets you know when an observer is active. This is useful when you want to start listening on location or sensor services. Such as:

public class MyLiveData extends LiveData<MyData> {

    public MyLiveData(Context context) {
        // Initialize service
    }

    @Override
    protected void onActive() {
        // Start listening
    }

    @Override
    protected void onInactive() {
        // Stop listening
    }
}
Copy the code

When not to inherit LiveData

You can also start some data loading services using onActive(), but unless you have a good reason, you don’t need to wait for LiveData to be observed. Some common patterns:

  • Add one to the ViewModelstart()Method and call it as soon as possible. [seeBlueprint for example]
  • Set a property to start the load [see GithubBrowserExample]

Usually you don’t inherit LiveData. Let your Activity or Fragment tell the ViewModel when to start loading data.

Original link:
ViewModels and LiveData: Patterns + AntiPatterns

Recommended reading

  • Developing a modern Android project with Kotlin Part 1

Aurora Daily,Aurora developerOwned media.

Read three English technical articles every day.