Dagger: How do we inject runtime arguments into the viewmodel?

Created on 11 Jun 2020  路  6Comments  路  Source: google/dagger

What if we wanted to have runtime arguments or other runtime arguments besides SavedStateHandle?

@AndroidEntryPoint
class TasksFragment : Fragment() {

    private val viewModel by viewModels<TasksViewModel>()

    private val args: TasksFragmentArgs by navArgs()

    private val argToInject get() = args.userMessage
....
class TasksViewModel @ViewModelInject constructor(
    private val tasksRepository: TasksRepository,
    @Assisted argToInject:Int,
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel()

@Assisted argToInject:Int isn't known to Dagger since we can't annotate argToInject with @Assisted, do we still have to use Assisted Inject by Square or there's another way?

P2 hilt

Most helpful comment

If you primarily want access to the safe args in the view model, you might want to look at https://issuetracker.google.com/issues/136967621. Doesn't seem to be getting much attention but that seems to be the obvious way to allow safe access from a SavedStateHandle.

All 6 comments

This isn't possible right now. This might be easier to do once we have assisted injection directly in Dagger (https://github.com/google/dagger/issues/1825) but there'd still be some work in ViewModelInject to expose the factory to you.

Unfortunately, if you need this today you'll need to write your own ViewModelFactory to hook it up yourself. You can still do what @ViewModelInject is doing though and use a Hilt @EntryPoint to grab things from Dagger in your factory though.

Looking at the code it seems that SavedStateHandle uses the fragment's arguments as defaultArgs so invoking the get method on a SavedStateHandle it's possible to retrieve the values. It's not documented so I am not sure if it's a "feature" or it just works.
@Chang-Eric what do you think?

Yes, I forgot to mention you can pass things through the bundle. I was mostly thinking of objects that can't be put in there.

Looking at the code it seems that SavedStateHandle uses the fragment's arguments as defaultArgs so invoking the get method on a SavedStateHandle it's possible to retrieve the values. It's not documented so I am not sure if it's a "feature" or it just works.
@Chang-Eric what do you think?

I know that the same bundle is provided as a SavedStateHandle in the ViewModel, but inside you still have to use, savedStateHandle.get("key") which eliminates the readability and abstraction that safeArgs provides and it's like using arguments.get("key"), thus you're limited to what the Bundle can store.

Thus if we use @Asssited from Square and at the same time use Hilt's Assisted there'd be name clash at first and it'll be a complete mess.

It'd be possible to expose the ViewModel factory when using @ViewModelInject so that we can add arguments?
As I see that the factory is done with Provider<ViewModelAssistedFactory<? extends ViewModel>>>, maybe another similar structure that'll offer a list of arguments to the factoryProvider.get().create(handle, runtimeArgs) or a way to feed it arguments by allowing us to create that factory?

If you primarily want access to the safe args in the view model, you might want to look at https://issuetracker.google.com/issues/136967621. Doesn't seem to be getting much attention but that seems to be the obvious way to allow safe access from a SavedStateHandle.

Was this page helpful?
0 / 5 - 0 ratings