ViewModel, SavedStateHandle and Dagger 2.31 assisted injection
On Medium there is an excellent post Saving UI state with ViewModel SavedState and Dagger. Nimrod Dayan shows the way how to combine Dagger’s injection and usage of SavedStateHandle in view models.
I use this solution in my projects, it works, but looks some difficult.
In release 2.31 Dagger gives us the ability to use assisted injection. And now I can create my view models in more simple way.
Here is my ViewModel: it uses aSavedStateHandle
and an useCase
.
class MyViewModel(
private val savedStateHandle: SavedStateHandle,
private val useCase: MyUseCaseContract.Input
) : ViewModel() {...}
Also I have a subcomponent:
@Subcomponent
interface MyComponent {
fun inject(activity: MyActivity)
}
Now I have to add myViewModel
to my activity.
Create an descendant class of AbstractSavedStateViewModelFactory
MyViewModelFactory
will provide instances of MyViewModel
. It uses new@AssistedInject
and @Assisted
annotations.
class MyViewModelFactory @AssistedInject constructor(
val useCase: MyUseCase.Input,
@Assisted owner: SavedStateRegistryOwner
) : AbstractSavedStateViewModelFactory(owner, null) { override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T = MyViewModel(handle, useCase) as T
}
Create an Assisted Factory
@AssistedFactory
interface MyViewModelAssistedFactory {
fun create(owner: SavedStateRegistryOwner): MyViewModelFactory
}
Activity
Now in activity I create an instance of MyViewModelFactory
and use that instance with ViewModelProvider
to create my viewModel
class MyActivity { @Inject
lateinit var assistedFactory: MyViewModelAssistedFactory
private lateinit var viewModel: MyViewModel
...
override fun onCreate(savedInstanceState: Bundle?) {
val myComponent = appComponent.myComponent
myComponent.inject(this)
val viewModelFactory = assistedFactory.create(this) viewModel = ViewModelProvider(this, viewModelFactory)[MyViewModel::class.java]
}
}
That’s all. Really easy.
P. S.
Here is another way to instantiate a viewModel:
@Inject
lateinit var assistedFactory: MyViewModelAssistedFactory
private val viewModel:MyViewModel by viewModels { assistedFactory.create(this)
}