Dagger version is 2.25.2.
I have two Android project modules: core
module & app
module.
In core
module, I defined for dagger CoreComponent
,
In app
module I have AppComponent
for dagger.
CoreComponet
in core project module:
@Component(modules = [MyModule::class])
@CoreScope
interface CoreComponent {
fun getMyRepository(): MyRepository
}
In core project module, I have a repository class, it doesn't belong to any dagger module but I use @Inject
annotation next to its constructor:
class MyRepository @Inject constructor() {
...
}
My app component:
@Component(modules = [AppModule::class], dependencies = [CoreComponent::class])
@featureScope
interface AppComponent {
fun inject(activity: MainActivity)
}
In MainActivity
:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coreComponent = DaggerCoreComponent.builder().build()
DaggerAppComponent
.builder()
.coreComponent(coreComponent)
.build()
.inject(this)
}
}
My project is MVVM architecture, In general:
MainActivity
hostsMyFragment
MyFragment
has a reference toMyViewModel
MyViewModel
has dependencyMyRepository
(as mentioned aboveMyRepository
is incore
module)
Here is MyViewModel
:
class MyViewModel : ViewModel() {
// Runtime error: lateinit property repository has not been initialize
@Inject
lateinit var repository: MyRepository
val data = repository.getData()
}
MyViewModel
is initialized in MyFragment:
class MyFragment : Fragment() {
lateinit var viewModel: MyViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
...
}
}
When I run my app, it crashes with runtime error:
kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialize
The error tells me dagger dependency injection does't work with my setup. So, what do I miss? How to get rid of this error?
==== update =====
I tried :
class MyViewModel @Inject constructor(private val repository: MyRepository): ViewModel() {
val data = repository.getData()
}
Now when I run the app, I get new error:
Caused by: java.lang.InstantiationException: class foo.bar.MyViewModel has no zero argument constructor
====== update 2 =====
Now, I created MyViewModelFactory
:
class MyViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>,
@JvmSuppressWildcards Provider<ViewModel>>): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
I updated MyFragment to be :
class MyFragment : Fragment() {
lateinit var viewModel: MyViewModel
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onAttach(context: Context) {
// inject app component in MyFragment
super.onAttach(context)
(context.applicationContext as MyApplication).appComponent.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// I pass `viewModelFactory` instance here, new error here at runtime, complaining viewModelFactory has not been initialized
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MyViewModel::class.java)
...
}
}
Now I run my app, I get new error:
kotlin.UninitializedPropertyAccessException: lateinit property viewModelFactory has not been initialized
What's still missing?