I am facing this issue in multi module android project with HILT.
kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized in MyViewModel
My modules are
'App Module'
@AndroidEntryPoint
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
viewModel.test()
}}
'ViewModel Module'
class MainViewModel @ViewModelInject constructor(private val repository: MyUsecase): ViewModel() {
fun test(){
repository.test()
}}
'UseCase Module'
class MyUsecase @Inject constructor() {
@Inject
lateinit var feature: Feature
fun doThing() {
feature.doThing()
}
@Module
@InstallIn(ApplicationComponent::class)
object FeatureModule {
@Provides
fun feature(realFeature: RealFeature): Feature = realFeature
}
}
'DataSource Module'
interface Feature {
fun doThing()
}
class RealFeature : Feature {
override fun doThing() {
Log.v("Feature", "Doing the thing!")
}
}
Dependencies are
MyFragment ---> MyViewModel ---> MyUseCase ---> DataSource
what i did wrong with this code pls correct it.
above your activity class you must add annotation @AndroidEntryPoint as below:
@AndroidEntryPoint class MainActivity : AppCompatActivity() {
In addition to moving all your stuff to constructor injection, your RealFeature
isn't being injected, because you instantiate it manually rather than letting Dagger construct it for you. Note how your FeatureModule directly calls the constructor for RealFeature and returns it for the @Provides
method. Dagger will use this object as is, since it thinks you've done all the setup for it. Field injection only works if you let Dagger construct it.
Your FeatureModule should look like this:
@Module
@InstallIn(ApplicationComponent::class)
object FeatureModule {
@Provides
fun feature(realFeature: RealFeature): Feature = realFeature
}
Or with the @Binds
annotation:
@Module
@InstallIn(ApplicationComponent::class)
interface FeatureModule {
@Binds
fun feature(realFeature: RealFeature): Feature
}
This also highlights why you should move to constructor injection; with constructor injection, this mistake wouldn't have been possible.
The problem in the code is that @ViewModelInject
doesn't work as @Inject
in other classes. You cannot perform field injection in a ViewModel.
You should do:
class MainViewModel @ViewModelInject constructor(
private val myUseCase: MyUsecase
): ViewModel() {
fun test(){
myUseCase.test()
}
}
Consider following the same pattern for the MyUsecase
class. Dependencies should be passed in in the constructor instead of being @Inject
ed in the class body. This kind of defeats the purpose of dependency injection.
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