Dagger: Hilt - is it possible to create a ViewModel annotated with @ViewModelInject that gets a SavedStateHandle which is initialized with navBackStackEntry.arguments?

Created on 18 Jun 2020  路  2Comments  路  Source: google/dagger

I'd like to initialize the SavedStateHandle from navBackStackEntry.arguments, and I think the Activity and the Fragment have their defaultViewModelProviderFactory overridden, but it seems unlikely that as AbstractSavedStateViewModelFactory requires the arguments as constructor argument, that the Hilt-generated factory would be able to know about the NavBackStackEntry.arguments.

So is there a way to get a Hilt-driven AbstractSavedStateViewModelFactory that can be used against the NavBackStackEntry (and combine ViewModel with @ViewModelInject and @Assisted)?

P2 hilt

Most helpful comment

If the back stack entry is for the same fragment destination, it turns out the fragment's arguments are the same as back stack entry, so using the @AndroidEntryPoint-annotated Fragment's defaultViewModelProviderFactory will give you a SavedStateHandle prepopulated with those args.

Meanwhile, I've been thinking of a more proper way to offer HiltViewModelFactory both for tests and these kind of situation were the integration is not as nice. Would having a default injectable binding of type HiltViewModelFactory.Builder for which you can supply the bundle for the SavedStateHandle and already contains the multibinding map of the assisted factories work for you?

Usage would be something like this:

@AndroidEntryPoint
class MyFragment : Fragment() {
  @Inject
  lateinit var hiltViewModelFactoryBuilder : HiltViewModelFactory.Builder

  val myViewModel by navGraphViewModels(R.id.vm_graph) { 
      hiltViewModelFactoryBuilder.build(findNavController().getBackStackEntry(R.id.vm_graph).arguments)
  }
}

All 2 comments

If the back stack entry is for the same fragment destination, it turns out the fragment's arguments are the same as back stack entry, so using the @AndroidEntryPoint-annotated Fragment's defaultViewModelProviderFactory will give you a SavedStateHandle prepopulated with those args.

Meanwhile, I've been thinking of a more proper way to offer HiltViewModelFactory both for tests and these kind of situation were the integration is not as nice. Would having a default injectable binding of type HiltViewModelFactory.Builder for which you can supply the bundle for the SavedStateHandle and already contains the multibinding map of the assisted factories work for you?

Usage would be something like this:

@AndroidEntryPoint
class MyFragment : Fragment() {
  @Inject
  lateinit var hiltViewModelFactoryBuilder : HiltViewModelFactory.Builder

  val myViewModel by navGraphViewModels(R.id.vm_graph) { 
      hiltViewModelFactoryBuilder.build(findNavController().getBackStackEntry(R.id.vm_graph).arguments)
  }
}

If the back stack entry is for the same fragment destination, it turns out the fragment's arguments are the same as back stack entry, so using the @AndroidEntryPoint-annotated Fragment's defaultViewModelProviderFactory will give you a SavedStateHandle prepopulated with those args.

Now that I think about it, the default args are only used for initialization, which means it's not possible to come back after process death on a non-start-destination without having already initialized the contents of the SavedStateHandle during the initial initialization (when the NavGraph was first entered, before process death). So indeed, there's a chance this actually doesn't pose an issue... for now, anyways. :thinking:

Would having a default injectable binding of type HiltViewModelFactory.Builder for which you can supply the bundle for the SavedStateHandle and already contains the multibinding map of the assisted factories work for you?

This would definitely solve the issue, if it's possible :slightly_smiling_face:

Was this page helpful?
0 / 5 - 0 ratings