ViewModel, SavedStateHandle and Dagger 2.31 assisted injection

Constantine Voronin
2 min readJan 20, 2021

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)
}

--

--