ViewModel scopes

rainbow-cake-dagger
rainbow-cake-koin

ViewModels by default are scoped to their Fragment, meaning a new instance is created for every new instance of the Fragment (barring configuration changes), and they are cleared when their Fragment is destroyed without recreation.

There are use cases where it would make sense to share ViewModel instances between Fragments. Both the Dagger 2 and Koin integrations of RainbowCake provide support for this in their getViewModelFromFactory methods, in the form of the optional scope parameter.

See the Dependency Injection page for more details about these two integrations.

Note that these ViewModel scopes only exist in terms of Fragment ViewModels, as Activity ViewModels are always scoped to their Activity.

Default scope

The default behavior of ViewModels, produced by the simplest provideViewModel implementation.

override fun provideViewModel() = getViewModelFromFactory()

A ViewModel with this scope is scoped to its Fragment. A new ViewModel will be created each time a Fragment using this scope is instantiated, and it will be cleared when the Fragment is destroyed.

This scope can also be made explicit by providing it as a parameter:

override fun provideViewModel() = getViewModelFromFactory(scope = Default)

Parent Fragment scope

A ViewModel with this scope is scoped to the parent of its Fragment.

override fun provideViewModel() = getViewModelFromFactory(scope = ParentFragment)

A parent Fragment must exist in this case, otherwise instantiation will fail. ViewModels in this scope will be cleared when the parent Fragment is destroyed. The typical use case for this scope is multiple nested Fragments that need to share data amongst themselves through a ViewModel, e.g. those in a ViewPager.

A key may be provided to scope multiple separate instances of the same ViewModel class within the same parent Fragment.

override fun provideViewModel() = getViewModelFromFactory(scope = ParentFragment("key"))

Activity scope

A ViewModel with this scope is scoped to the current Activity.

override fun provideViewModel() = getViewModelFromFactory(scope = Activity)

ViewModels in this scope will only be cleared when this Activity is destroyed, meaning they might exist long after any Fragments using them have been destroyed.

A key may be provided to scope multiple separate instances of the same ViewModel class within the same Activity.

override fun provideViewModel() = getViewModelFromFactory(scope = Activity("key"))

If no key is provided, the ViewModel will essentially exist as a singleton within the single Activity of the application. This is the recommended way for creating singleton ViewModel instances, as opposed to having them managed by Dagger, which takes the control away from the ViewModelProvider API, and can lead to unexpected behaviour (consider coroutine cancellation in this case!).

While not currently part of the architecture library, the following typealias may be used to make this intention more explicit:

typealias Singleton = ViewModelScope.Activity

override fun provideViewModel() = getViewModelFromFactory(scope = Singleton)