diff --git a/hilt/view-model.md b/hilt/view-model.md index abdce959a7b..083877a3277 100644 --- a/hilt/view-model.md +++ b/hilt/view-model.md @@ -168,3 +168,133 @@ class MovieViewModel @Inject constructor( } ``` {: .c-codeselector__code .c-codeselector__code_kotlin } + +## Assisted Injection + +Hilt View Models can also be +[assisted injected](https://dagger.dev/dev-guide/assisted-injection). Compared +to using `SavedStateHandle`, this enables passing data that are not `Parcelable` +to a Hilt View Model easily. To use asssited injection, annotate the view model +constructor with `@AssistedInject` and the assisted parameters with `@Assisted`, +and specify the assisted factory in the `@HiltViewModel` annotation: + +
Java
+ +
Kotlin
+ +```java +@HiltViewModel(assistedFactory = MovieViewModelFactory.class) +class MovieViewModel { + @AssistedInject MovieViewModel(@Assisted int movieId) { + // ... + } +} +``` +{: .c-codeselector__code .c-codeselector__code_java } + +```kotlin +@HiltViewModel(assistedFactory = MovieViewModelFactory::class) +class MovieViewModel @AssistedInject constructor( + @Assisted val movieId: Int +) : ViewModel { + // ... +} +``` +{: .c-codeselector__code .c-codeselector__code_kotlin } + +**Note:** Unlike `SavedStateHandle`, the values passed through assisted +parameters to a Hilt View Model do not get saved to disk. They have the same +scope as the view model and do not persist after the lifecycle of the view model +has ended, e.g. containing activity gets popped off the stack or process death. +Consider using normal injection with `SavedStateHandle` instead or other +mechanisms if persistence is needed. +{: .c-callouts__note} + +Next, define the assisted factory with an abstract factory method that returns +the view model: + +
Java
+ +
Kotlin
+ +```java +@AssistedFactory +interface MovieViewModelFactory { + MovieViewModel create(int movieId); +} +``` +{: .c-codeselector__code .c-codeselector__code_java } + +```kotlin +@AssistedFactory +interface MovieViewModelFactory { + fun create(val movieId: Int): MovieViewModel +} +``` +{: .c-codeselector__code .c-codeselector__code_kotlin } + +**Note:** It is an error to request the assisted factory for view models from +Dagger directly since the factory may be used to create view model instances +that are not stored correctly. This is checked at compile time by Hilt. +{:.c-callouts__note} + +Finally, pass a callback to the helper function +`HiltViewModelExtensions.withCreationCallback()` to create a `CreationExtras` +that can be used with the `ViewModelProvider` API or other view model functions +like `by viewModels()`. Use the passed in factory to create a view model +instance inside the callback: + +
Java
+ +
Kotlin
+ +```java +@AndroidEntryPoint +public final class MyActivity extends AppCompatActivity { + + private int movieId = 1; + private MovieViewModel movieViewModel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + movieViewModel = new ViewModelProvider( + getViewModelStore(), + getDefaultViewModelProviderFactory(), + HiltViewModelExtensions.withCreationCallback( + getDefaultViewModelCreationExtras(), + (MyViewModel.Factory factory) -> factory.create(movieId))) + .get(MyInjectedViewModel.class); + } +} +``` +{: .c-codeselector__code .c-codeselector__code_java } + +```kotlin +@AndroidEntryPoint +class MyActivity : AppCompatActivity() { + private val movieId = 1 + private val movieViewModel by viewModels( + extrasProducer = { + defaultViewModelCreationExtras.withCreationCallback< + MovieViewModelFactory> { factory -> + factory.create(movieId) + } + } + ) +} +``` +{: .c-codeselector__code .c-codeselector__code_kotlin } + +**Warning:** Do not pass any objects that have a smaller lifecycle than the +view model (e.g. an `Activity`, `Fragment`, or `View`) or any objects that +reference them to the assisted factory as that would be leaking them. +{: .c-callouts__warning} + +**Note:** Unlike normal `@AssistedInject` types, a Hilt View Models, like all +View Models, are memoized by the owner. Once a Hilt View Model instance has been +created, the callback will be ignored as long as the view model's lifecycle has +not ended. For example, Hilt does not call the callback to create a new view +model instance after configuration changes, nor will it update the values of +assisted parameters in the existing view model instances. +{: .c-callouts__note}