Skip to content

Commit

Permalink
Add assisted injection section to the view model doc
Browse files Browse the repository at this point in the history
RELNOTES=n/a
PiperOrigin-RevId: 574504036
  • Loading branch information
kuanyingchou authored and Dagger Team committed Nov 1, 2023
1 parent 9c8eb32 commit 830e0d5
Showing 1 changed file with 130 additions and 0 deletions.
130 changes: 130 additions & 0 deletions hilt/view-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<div class="c-codeselector__button c-codeselector__button_java">Java</div>

<div class="c-codeselector__button c-codeselector__button_kotlin">Kotlin</div>

```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:

<div class="c-codeselector__button c-codeselector__button_java">Java</div>

<div class="c-codeselector__button c-codeselector__button_kotlin">Kotlin</div>

```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:

<div class="c-codeselector__button c-codeselector__button_java">Java</div>

<div class="c-codeselector__button c-codeselector__button_kotlin">Kotlin</div>

```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<MovieViewModel>(
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}

0 comments on commit 830e0d5

Please sign in to comment.