Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get access to Arguments/Extras Bundle in ViewModel with minimal boilerplate using Dagger 2?

I'm transitioning my app to use ViewModels. For instantiating the ViewModels I use a custom Factory and Dagger 2 for dependency injection. It looks like this:

@Singleton
class ViewModelFactory @Inject constructor(
    private val viewModels: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T 
        = viewModels[modelClass]!!.get() as T
}

@Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

@Module
abstract class ViewModelModule {

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds @IntoMap @ViewModelKey(FooViewModel::class)
    abstract fun fooViewModel(viewModel: FooViewModel): ViewModel
}

Now I'm facing the question, how to access the Arguments/Extras Bundle of my Fragment or Activity inside a ViewModel. This is necessary because the views and therefore the data in the ViewModel is often parametrizable. How would I implement this using the least amount of boilerplate?

like image 666
Kirill Rakhman Avatar asked Oct 08 '18 11:10

Kirill Rakhman


People also ask

Can I use bundle in ViewModel?

We only need to read from a saved Bundle when the ViewModel gets created, not when it is reused. The Activity or Fragment does not know this, so it is the wrong class to add this to. But there is the ViewModelProvider. Factory that creates the ViewModel.

How do you inject a ViewModel with a dagger?

Setup a Dagger 2 Module Then setup the Dagger 2 Module with that provide the ViewModel. Like normal ViewModel creation, use ViewModelProvider and the Factory to create it. We'll need to pass in the dependencies which can be automatically injected by Dagger 2 using the conventional approach.

How do you inject ViewModel in activity?

The koin-android Gradle module introduces a new viewModel DSL keyword that comes in complement of single and factory , to help declare a ViewModel component and bind it to an Android Component lifecycle. Your declared component must at least extends the android.

Should view models be injected?

The viewModels() extension function is provided by androidx KTX . Even if the ViewModel has savedStateHandle or is taking the intent bundle from the Activity, it doesn't need to be explicitly injected in. The viewModels() extension function does all that automatically behind the scene.


1 Answers

If you use Saved State module, both activity intent extras and fragment arguments are available via SavedStateHandle

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {
  init {
    val someArgument = state.get<String>("someArgumentKey")
    ...
  }
}

You can also use AssistedInject library to pass arguments from an Activity/Fragment into a ViewModel, but it's a boilerplate solution. Here's a dagger example, and another one which uses dagger hilt.

like image 162
Valeriy Katkov Avatar answered Sep 30 '22 17:09

Valeriy Katkov