Skip to content

Most visited

Recently visited

navigation

ViewModel

The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.

App components, like activities and fragments, have a lifecycle managed by the Android Framework. The Framework may decide to destroy or re-create them based on some user actions or device events that are completely out of your control.

Since these objects might be destroyed or re-created by the operating system, any data you hold in them is lost. For instance, if you have a list of users in your activity, when the activity is re-created for a configuration change, the new activity has to re-fetch the list of users. For simple data, the activity can use the onSaveInstanceState() method and restore its data from the bundle in onCreate(), but this approach is only suitable for small amounts of data like UI state, not for potentially large amounts of data like a list of users.

Another problem is that, these UI controllers (activities, fragments, and so on) frequently need to make some asynchronous calls which may take some time to return. The UI controller needs to manage these calls and clean them up when it is destroyed to avoid potential memory leaks. This requires a lot of maintenance, and in the case where the object is re-created for a configuration change, it is a waste of resources since it needs to re-issue the same call.

Last but not least, these UI controllers already need to react to user actions or handle the operating system communication. When they also need to handle their resources manually, it bloats the class, creating "god activities" (or "god fragments"); that is, a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes. This also makes testing a lot harder.

It is easier and more efficient to separate out view data ownership from UI controller logic. Lifecycles provides a new class called ViewModel, a helper class for the UI controller which is responsible for preparing the data for the UI. The ViewModel is automatically retained during configuration changes so that the data it holds is immediately available to the next activity or fragment instance. In the example we’ve mentioned above, it should be the ViewModel’s responsibility to acquire and keep the list of users, not the activity or the fragment.

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
    }
}

Now the activity can access this list as follows:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

If the activity is re-created, it receives the same MyViewModel instance that was created by the previous activity. When the owner activity is finished, the Framework calls ViewModel’s onCleared() method so that it can clean up resources.

Sharing Data Between Fragments

It is very common that two or more fragments in an activity need to communicate with each other. This is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. Moreover, both fragments must handle the case where the other fragment is not yet created or not visible.

This common pain point can be addressed by using ViewModel objects. Imagine a common case of master-detail fragments, where we have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item.

These fragments can share a ViewModel using their activity scope to handle this communication.

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

Notice that both fragments are using getActivity() while getting the ViewModelProvider. This means both of them will receive the same SharedViewModel instance, which is scoped to the activity.

Benefits of this approach include:

The lifecycle of a ViewModel

ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel stays in memory until the Lifecycle it’s scoped to goes away permanently—in the case of an activity, when it finishes; in the case of a fragment, when it’s detached.

ViewModel vs SavedInstanceState

ViewModels provide a convenient way to retain data across configuration changes but they are not persisted if the application is killed by the operating system.

For example, if the user leaves the application and comes back hours later, the process will be killed by that time and the Android OS will restore the Activity from the saved state. All framework components (views, activities, fragments) save their state using saved instance state mechanism so most of the time, you don't have to do anything. You can add custom data into this bundle using the onSaveInstanceState callback.

The data saved via onSaveInstanceState is kept in the system process memory and the Android OS allows you to keep only a very small amount of data so it is not a good place to keep actual data for your app. You should sparingly use it for things that are not easily represented by UI components.

For example, if you have a user interface that shows information about a Country, you should never put the Country object into the saved instance state. You can put the countryId into the saved state (unless it is already saved by a View or Fragment arguments). The actual object should live in a database and the ViewModel can retrieve it using the saved countryId.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.