One of the most up to date samples covering Android Architecture Components is GithubBrowserSample provided by Google. I reviewed the code and a few questions arose:
I have noticed that ViewModelModule is included in AppModule. It means that all the viewmodels are added to the DI graph. Why that is done in that way instead of having separate Module
for each Activity/Fragment that would provide only needed ViewModel
for specific Activity/Fragment?
In this specific example, where viewmodels are instantiated using GithubViewModelFactory is there any way to pass a parameter to the specific ViewModel
? Or the better solution would be to create a setter in ViewModel
and set needed param via setter?
Android Architecture Components provides the ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes we will see that in the below example. Now let’s get into the code, Step 1: Add these dependencies in the build.gradle file
Thanks to this, at Google I/O 2017 the Android Framework team introduced a new Architecture Component which deals this kind of rotation. The ViewModel class is designed to store and manage UI-related data in a conscious way. The ViewModel is able to live through the configuration changes.
For more information, see Use Kotlin coroutines with Android Architecture Components. As your data grows more complex, you might choose to have a separate class just to load the data. The purpose of ViewModel is to encapsulate the data for a UI controller to let the data survive configuration changes.
If the ViewModel needs the Application context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the Application in the constructor, since Application class extends Context. ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel.
- [...] It means that all the viewmodels are added to the DI graph. Why that is done in that way instead of having separate Module for each Activity/Fragment [...]?
They are added to the DI graph, but they are not yet created. Instead they end up in a map of providers, as seen in the ViewModelFacory.
@Inject
public GithubViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) { }
So we now have a GithubViewModelFactory
that has a list of providers and can create any ViewModel
that was bound. Fragments and Activities can now just inject the factory and retrieve their ViewModel.
@Inject
ViewModelProvider.Factory viewModelFactory;
// ...later...
repoViewModel = ViewModelProviders.of(this, viewModelFactory).get(RepoViewModel.class);
As to the why...alternatively you could create a ViewModelProvider.Factory
for every Activity / Fragment and register the implementation in every Module. This would be a lot of duplicated boilerplate code, though.
- In this specific example, where viewmodels are instantiated using GithubViewModelFactory is there any way to pass a parameter to the specific ViewModel? Or the better solution would be to create a setter in ViewModel and set needed param via setter?
It seems like all the ViewModels only depend on @Singleton
objects—which is necessary, since they all get provided from the AppComponent. This means that there is no way to pass in "parameters" other than other @Singleton
dependencies.
So, as you suggested, you'd either have to move the factory down into the Activity / Fragment component so that you can provide lower-scoped dependencies, or use a setter method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With