Stay organized with collections Save and categorize content based on your preferences.

ViewModel overview   Part of Android Jetpack.

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

The Android framework manages the lifecycle of UI controllers, such as activities and fragments. The framework may decide to destroy or re-create a UI controller in response to certain user actions or device events that are completely out of your control.

If the system destroys or re-creates a UI controller, any transient UI-related data you store in them is lost. For example, your app may include a list of users in one of its activities. 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 that can be serialized then deserialized, not for potentially large amounts of data like a list of users or bitmaps.

Another problem is that UI controllers frequently need to make asynchronous calls that may take some time to return. The UI controller needs to manage these calls and ensure the system cleans them up after it's destroyed to avoid potential memory leaks. This management requires a lot of maintenance, and in the case where the object is re-created for a configuration change, it's a waste of resources since the object may have to reissue calls it has already made.

UI controllers such as activities and fragments are primarily intended to display UI data, react to user actions, or handle operating system communication, such as permission requests. Requiring UI controllers to also be responsible for loading data from a database or network adds bloat to the class. Assigning excessive responsibility to UI controllers can result in a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes. Assigning excessive responsibility to the UI controllers in this way also makes testing a lot harder.

It's easier and more efficient to separate out view data ownership from UI controller logic.

Implement a ViewModel

Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment, as illustrated by the following sample code:

Views

class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData<List<User>>().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

Views

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

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

You can then access the list from an activity as follows:

Views

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val model: MyViewModel by viewModels()
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}

Views

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = new ViewModelProvider(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 first activity. When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources.

ViewModel objects are designed to outlive specific instantiations of views or LifecycleOwners. This design also means you can write tests to cover a ViewModel more easily as it doesn't know about view and Lifecycle objects. ViewModel objects can contain LifecycleObservers, such as LiveData objects. However ViewModel objects must never observe changes to lifecycle-aware observables, such as LiveData objects. If the ViewModel needs the Application context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor, since Application class extends Context.

Create ViewModels with dependencies

Following dependency injection's best practices, ViewModels can take dependencies as parameters in their constructor. These are mostly of types from the domain or data layers. Because the framework provides the ViewModels, a special mechanism is required to create instances of them. That mechanism is the ViewModelProvider.Factory interface. Only implementations of this interface can instantiate ViewModels in the right scope.

If a ViewModel class receives dependencies in its constructor, provide a factory that implements the ViewModelProvider.Factory interface. Override the create(Class<T>, CreationExtras) function to provide a new instance of the ViewModel.

CreationExtras allows you to access relevant information that helps instantiate a ViewModel. Here's a list of keys that can be accessed from extras:

Key Functionality
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY This Key provides access to the custom key you passed to ViewModelProvider.get().
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY Provides access to the instance of the Application class.
SavedStateHandleSupport.DEFAULT_ARGS_KEY Provides access to the Bundle of arguments you should use to construct a SavedStateHandle.
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY Provides access to the SavedStateRegistryOwner that is being used to construct the ViewModel.
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY Provides access to the ViewModelStoreOwner that is being used to construct the ViewModel.

To create a new instance of SavedStateHandle, use the CreationExtras.createSavedStateHandle().createSavedStateHandle()) function and pass it to the ViewModel.

The following is an example of how to provide an instance of a ViewModel that takes a repository scoped to the Application class and SavedStateHandle as dependencies:

Views

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.CreationExtras

class MyViewModel(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    // ViewModel logic
    // ...

    // Define ViewModel factory in a companion object
    companion object {

        val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
            @Suppress("UNCHECKED_CAST")
            override fun <T : ViewModel> create(
                modelClass: Class<T>,
                extras: CreationExtras
            ): T {
                // Get the Application object from extras
                val application = checkNotNull(extras[APPLICATION_KEY])
                // Create a SavedStateHandle for this ViewModel from extras
                val savedStateHandle = extras.createSavedStateHandle()

                return MyViewModel(
                    (application as MyApplication).myRepository,
                    savedStateHandle
                ) as T
            }
        }
    }
}

Views

import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;

import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;

public class MyViewModel extends ViewModel {

    public MyViewModel(
        MyRepository myRepository,
        SavedStateHandle savedStateHandle
    ) { /* Init ViewModel here */ }

    static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
        MyViewModel.class,
        creationExtras -> {
            MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
            assert app != null;
            SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);

            return new MyViewModel(app.getMyRepository(), savedStateHandle);
        }
    );
}

Then, you can use this factory when retrieving an instance of the ViewModel:

Views

import androidx.activity.viewModels

class MyActivity : AppCompatActivity() {

    private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }

    // Rest of Activity code
}

Views

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;

public class MyActivity extends AppCompatActivity {

    MyViewModel myViewModel = new ViewModelProvider(
        this,
        ViewModelProvider.Factory.from(MyViewModel.initializer)
    ).get(MyViewModel.class);

    // Rest of Activity code
}

Compose

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
    // ...
}

Alternatively, use the ViewModel factory DSL to create factories using a more idiomatic Kotlin API:

Views

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory

class MyViewModel(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    // ViewModel logic

    // Define ViewModel factory in a companion object
    companion object {
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                val savedStateHandle = createSavedStateHandle()
                val myRepository = (this[APPLICATION_KEY] as MyApplication).myRepository
                MyViewModel(
                    myRepository = myRepository,
                    savedStateHandle = savedStateHandle
                )
            }
        }
    }
}

Factories for ViewModel version older than 2.5.0

If you're using a version of ViewModel older than 2.5.0, you need to provide factories from a subset of classes that extend ViewModelProvider.Factory and implement the create(Class<T>) function. Depending on what dependencies the ViewModel needs, a different class needs to be extended from:

If Application or SavedStateHandle aren't needed, simply extend from ViewModelProvider.Factory.

The following example uses an AbstractSavedStateViewModelFactory for a ViewModel that takes a repository and a SavedStateHandle type as a dependency:

Views

class MyViewModel(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    // ViewModel logic ...

    // Define ViewModel factory in a companion object
    companion object {
        fun provideFactory(
            myRepository: MyRepository,
            owner: SavedStateRegistryOwner,
            defaultArgs: Bundle? = null,
        ): AbstractSavedStateViewModelFactory =
            object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
                @Suppress("UNCHECKED_CAST")
                override fun <T : ViewModel> create(
                    key: String,
                    modelClass: Class<T>,
                    handle: SavedStateHandle
                ): T {
                    return MyViewModel(myRepository, handle) as T
                }
            }
    }
}

Views

import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;

public class MyViewModel extends ViewModel {
    public MyViewModel(
        MyRepository myRepository,
        SavedStateHandle savedStateHandle
    ) { /* Init ViewModel here */ }
}

public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {

    private final MyRepository myRepository;

    public MyViewModelFactory(
        MyRepository myRepository
    ) {
        this.myRepository = myRepository;
    }

    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    protected <T extends ViewModel> T create(
        @NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
    ) {
        return (T) new MyViewModel(myRepository, handle);
    }
}

Then, you can use factory to retrieve your ViewModel:

Views

import androidx.activity.viewModels

class MyActivity : AppCompatActivity() {

    private val viewModel: MyViewModel by viewModels {
        MyViewModel.provideFactory((application as MyApplication).myRepository, this)
    }

    // Rest of Activity code
}

Views

public class MyActivity extends AppCompatActivity {

    MyViewModel myViewModel = new ViewModelProvider(
        this,
        new MyViewModelFactory(((MyApplication) getApplication()).getMyRepository())
    ).get(MyViewModel.class);

    // Rest of Activity code
}

Compose

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(
        factory = MyViewModel.provideFactory(
            (LocalContext.current.applicationContext as MyApplication).myRepository,
            owner = LocalSavedStateRegistryOwner.current
        )
    )
) {
    // ...
}

The lifecycle of a ViewModel

ViewModel objects are scoped to the Lifecycle of the ViewModelStoreOwner passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the ViewModelStoreOwner 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.
  • In the case of a Navigation entry, when it's removed from the back stack.

This makes ViewModels a great solution for storing data that survives configuration changes.

Figure 1 illustrates the various lifecycle states of an activity as it undergoes a rotation and then is finished. The illustration also shows the lifetime of the ViewModel next to the associated activity lifecycle. This particular diagram illustrates the states of an activity. The same basic states apply to the lifecycle of a fragment.

Illustrates the lifecycle of a ViewModel as an activity changes state.

You usually request a ViewModel the first time the system calls an activity object's onCreate() method. The system may call onCreate() several times throughout the life of an activity, such as when a device screen is rotated. The ViewModel exists from when you first request a ViewModel until the activity is finished and destroyed.

ViewModel APIs

The ViewModelProvider.get() method lets you obtain an instance of a ViewModel scoped to any ViewModelStoreOwner. For Kotlin users, there are different extension functions available for the most common use cases. All Kotlin extension function implementations use the ViewModelProvider API under the hood.

ViewModels scoped to the closest ViewModelStoreOwner

You can scope a ViewModel to an Activity, Fragment, or destination of a Navigation graph. The viewModels() extension functions provided by the Activity, Fragment and Navigation libraries, and the viewModel() function in Compose allows you to get an instance of the ViewModel scoped to the closest ViewModelStoreOwner.

Views

class MyActivity : AppCompatActivity() {

    // ViewModel API available in activity.activity-ktx
    // The ViewModel is scoped to `this` Activity
    val viewModel: MyViewModel by viewModels()
}

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to `this` Fragment
    val viewModel: MyViewModel by viewModels()
}

Views

public class MyActivity extends AppCompatActivity {

    // The ViewModel is scoped to `this` Activity
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

public class MyFragment extends Fragment {

    // The ViewModel is scoped to `this` Fragment
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

Compose

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the closest ViewModelStoreOwner provided
    // via the LocalViewModelStoreOwner CompositionLocal. This could be the
    // host Activity or Fragment, or destination of the Navigation graph.
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

ViewModels scoped to any ViewModelStoreOwner

The ComponentActivity.viewModels() and Fragment.viewModels() functions in the View system and the viewModel() function in Compose take an optional ownerProducer parameter that you can use to specify to which ViewModelStoreOwner the instance of the ViewModel is scoped to. The following sample shows how to get an instance of a ViewModel scoped to the parent fragment:

Views

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the parent of `this` Fragment
    val viewModel: SharedViewModel by viewModels(
        ownerProducer = { requireParentFragment() }
    )
}

Views

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the parent of `this` Fragment
        viewModel = new ViewModelProvider(requireParentFragment())
            .get(SharedViewModel.class);
    }
}

Compose

@Composable
fun MyScreen(
    context: Context = LocalContext.current,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the parent of the host Fragment
    // where this composable function is called
    viewModel: SharedViewModel = viewModel(
        viewModelStoreOwner = (context as Fragment).requireParentFragment()
    )
) { /* ... */ }

As getting an Activity-scoped ViewModel from a Fragment can be a common use case in your app, the activityViewModels() Views extension function is available. If you're not using Views and Kotlin, you can use the same APIs as above and passing the right owner.

Views

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the host Activity
    val viewModel: SharedViewModel by activityViewModels()
}

Views

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the host Activity
        viewModel = new ViewModelProvider(requireActivity())
            .get(SharedViewModel.class);
    }
}

Compose

@Composable
fun MyScreen(
    context: Context = LocalContext.current,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the Activity of the host Fragment
    // where this composable function is called
    viewModel: SharedViewModel = viewModel(
        viewModelStoreOwner = (context as Fragment).requireActivity()
    )
) { /* ... */ }

ViewModels scoped to the Navigation graph

Navigation graphs are also ViewModel store owners. If you're using Navigation Fragment or Navigation Compose, you can get an instance of a ViewModel scoped to a Navigation graph with the navGraphViewModels(graphId) Views extension function.

Views

class MyFragment : Fragment() {

    // ViewModel API available in navigation.navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    val viewModel: SharedViewModel by navGraphViewModels(R.id.nav_graph)

    // Equivalent navGraphViewModels code using the viewModels API
    val viewModel: SharedViewModel by viewModels(
        { findNavController().getBackStackEntry(R.id.nav_graph) }
    )
}

Views

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        viewModel = new ViewModelProvider(backStackEntry).get(SharedViewModel.class);
    }
}

Compose

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }
        // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph
        val parentViewModel: SharedViewModel = viewModel(parentEntry)
        // ...
    }
}

If you're using Hilt in addition to Jetpack Navigation, you can use the hiltNavGraphViewModels(graphId) API as follows.

Views

class MyFragment : Fragment() {

    // ViewModel API available in hilt.hilt-navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    // and is provided using the Hilt-generated ViewModel factory
    val viewModel: SharedViewModel by hiltNavGraphViewModels(R.id.nav_graph)
}

Views

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        viewModel = new ViewModelProvider(
            backStackEntry,
            HiltViewModelFactory.create(getContext(), backStackEntry)
        ).get(SharedViewModel.class);
    }
}

Compose

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }

        // ViewModel API available in hilt.hilt-navigation-compose
        // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        val parentViewModel: SharedViewModel = hiltViewModel(parentEntry)
        // ...
    }
}

Share data between fragments

It's very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of split-view (list-detail) fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.

This common pain point can be addressed by using ViewModel objects. These fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code:

Views

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData()

    fun select(item: Item) {
        selected.value = item
    }
}

class ListFragment : Fragment() {

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.selected.observe(viewLifecycleOwner, Observer { item ->
            // Update the UI
        })
    }
}

Views

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

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

    public LiveData getSelected() {
        return selected;
    }
}


public class ListFragment extends Fragment {
    private SharedViewModel model;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), item -> {
           // Update the UI.
        });
    }
}

Notice that both fragments retrieve the activity that contains them. That way, when the fragments each get the ViewModelProvider, they receive the same SharedViewModel instance, which is scoped to this activity.

This approach offers the following benefits:

  • The activity does not need to do anything, or know anything about this communication.
  • Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
  • Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.

Replacing Loaders with ViewModel

Loader classes like CursorLoader are frequently used to keep the data in an app's UI in sync with a database. You can use ViewModel, with a few other classes, to replace the loader. Using a ViewModel separates your UI controller from the data-loading operation, which means you have fewer strong references between classes.

In one common approach to using loaders, an app might use a CursorLoader to observe the contents of a database. When a value in the database changes, the loader automatically triggers a reload of the data and updates the UI:

Figure 2. Loading data with loaders

ViewModel works with Room and LiveData to replace the loader. The ViewModel ensures that the data survives a device configuration change. Room informs your LiveData when the database changes, and the LiveData, in turn, updates your UI with the revised data.

Figure 3. Loading data with ViewModel

Use coroutines with ViewModel

ViewModel includes support for Kotlin coroutines. For more information, see Use Kotlin coroutines with Android Architecture Components.

Further information

As your data grows more complex, you might choose to have a separate class just to load the data. The purpose of ViewModel is to encapsulate the data for a UI controller to let the data survive configuration changes. For information about how to load, persist, and manage data across configuration changes, see Saving UI States.

The Guide to Android App Architecture suggests building a repository class to handle these functions.

Additional resources

For further information about the ViewModel class, consult the following resources.

Samples

Codelabs

Blogs

Videos