Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of injecting a ViewModelFactory in Android - Dagger 2

I have recently started with Android Development, and coming from an iOS background, concepts like Dependency Injection frameworks and ViewModelFactories are a new thing for me. In all the tutorials I saw, ViewModels always extended the ViewModel class provided by android.arch.lifecycle.ViewModel. If the viewModel had parameters then a ViewModelFactory had to be created and injected in an activity by Dagger

@Provides
@ActivityScope
fun provideViewModelFactory(dependency: Dependency) : ViewModelProvider.Factory = CustomViewModelFactory(dependency)

CustomViewModelFactory will then be in charge of creating ViewModels. This all works fine, however, I'm not really understanding the point of a viewModelFactory when I can just inject the viewModels directly into an activity sort of like this:

@Module
class ViewModelModule(private val user: User) {
    @ActivityScope
    @Provides
    fun provideMainViewModel() = MainViewModel(user = user)
    fun provideOtherViewModel() = OtherViewModel()
}

@ActivityScope
@Subcomponent(modules = [ViewModelModule::class])
interface MainActivitySubComponent {
    fun inject(activity: MainActivity)
}

@ApplicationScope
@Component()
interface ApplicationComponent {
    fun addMainActivitySubComponent(viewModelModule: ViewModelModule) : MainActivitySubComponent
}

And in my Activity

class MainActivity : AppCompatActivity() {

    @Inject lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val subComponent = (application as MainApplication).component.addMainActivitySubComponent(ViewModelModule(User("NEW NAME")))

        subComponent.inject(this)
    }
}

So what is the point of a ViewModelFactory when I can simply inject a viewModel to in my activity right away?

like image 859
Nader Besada Avatar asked Jul 27 '18 16:07

Nader Besada


People also ask

What is the Viewmodelfactory interface for?

Implementations of ViewModelProviders. Factory interface are responsible to instantiate ViewModels. That means you write your own implementation for creating an instance of ViewModel.

What does inject mean in dagger?

inject(this); } The injector class used in Dagger 2 is called a component. It assigns references in our activities, services, or fragments to have access to singletons we earlier defined. We will need to annotate this class with a @Component annotation.

Should viewModels 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.

What is the use of dependency injection in Android?

Dependency injection provides your app with the following advantages: Reusability of classes and decoupling of dependencies: It's easier to swap out implementations of a dependency.


2 Answers

Let's take a look at what happens when you inject your ViewModel:

  1. Your Activity gets (re)created.
  2. You create a (Sub)Component for said Activity.
  3. You inject the dependencies.

The interesting part is 3, where we will inject some scoped objects (e.g. Singletons) but create new objects for the rest of our dependencies.

Every time you (re)create your Activity (-> configuration change) those objects will be created again, and you'll lose state. You can use savedInstanceState to preserve some data, or you could figure out some other means to save state (e.g. Singletons, retained Fragments, ...)


ViewModel on the other hand promises to keep state between orientation changes. When we request a ViewModel from ViewModelProviders after an orientation change we will receive the same object as before. We don't need to worry about saving and restoring the state.

We would recreate the factory, but Android/ the Support Library/Jetpack/Arch Components (whatever it's called now) will store the Viewmodel and only create it when it hasn't been created before. The previous model will be reused during configuration changes.


So if you want to inject the ViewModel directly you can obviously do so, but your ViewModel won't keep its state between orientation changes.

like image 187
David Medenjak Avatar answered Oct 08 '22 05:10

David Medenjak


You use the ViewModelProviders and the ViewModelProviders.Factory to ensure that you get the same instance of ViewModel across configuration changes. So in the scope of an Activity, the ViewModel created by the ViewModelProviders is only created once.

It's also required for expected behavior of the onCleared() callback that ViewModels have.

In Kotlin, I prefer to use this linked approach compared to the multi-binding one. Although it does require you to know about the "injector" who can create the view model.

like image 36
EpicPandaForce Avatar answered Oct 08 '22 07:10

EpicPandaForce