class SlideshowViewModel : ViewModel() {
@Inject lateinit var mediaItemRepository : MediaItemRepository
fun init() {
What goes here?
}
So I'm trying to learn Dagger2 so I can make my apps more testable. Problem is, I've already integrated Kotlin and am working on the Android Architectural components. I understand that constructor injection is preferable but this isn't possible with ViewModel
. Instead, I can use lateinit
in order to inject but I'm at a loss to figure out how to inject.
Do I need to create a Component
for SlideshowViewModel
, then inject it? Or do I use the Application
component?
gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
kapt {
generateStubs = true
}
dependencies {
compile "com.google.dagger:dagger:2.8"
annotationProcessor "com.google.dagger:dagger-compiler:2.8"
provided 'javax.annotation:jsr250-api:1.0'
compile 'javax.inject:javax.inject:1'
}
Application Component
@ApplicationScope
@Component (modules = PersistenceModule.class)
public interface ApplicationComponent {
void injectBaseApplication(BaseApplication baseApplication);
}
BaseApplication
private static ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent
.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseApplication(this);
}
public static ApplicationComponent getComponent() {
return component;
}
Try with below code :
No. You create a component where you are declaring (using) your viewModel. It is normally an activity/fragment. The viewModel has dependencies (mediaitemrepository), so you need a factory. Something like this:
Then the dagger part (activity module)
I wrote a library that should make this more straightforward and way cleaner, no multibindings or factory boilerplate needed, while also giving the ability to further parametrise the
ViewModel
at runtime: https://github.com/radutopor/ViewModelFactoryIn the view:
You can enable constructor injection for your ViewModels. You can check out Google samples to see how to do it in Java. (Update: looks like they converted the project to Kotlin so this URL no longer works)
Here is how to do a similar thing in Kotlin:
Add ViewModelKey annotation:
Add ViewModelFactory:
Add ViewModelModule:
Register your ViewModelModule in your component
Inject ViewModelProvider.Factory in your activity:
Pass your modelFactory to each ViewModelProviders.of method:
Here is the sample commit which contains all of the required changes: Support constructor injection for view models
Refer to a repo I created when I was learning dagger+kotlin
Essentially you need a ViewModelFactory instance to the UI layer, you use that to create a viewmodel.
Your ViewModelModule should look like (this is where you store all viewmodels).
Then create a dagger map key
Then on your UI layer, inject the factory and instantiate your viewmodel using ViewModelProviders
Assuming you have a
Repository
class that can be injected by Dagger and aMyViewModel
class that has a dependency onRepository
defined as such:Now you can create your
ViewModelProvider.Factory
implementation:Dagger setup does not look too complicated:
Here's the activity class (might be fragment as well), where the actual injection takes place: