我在使用HILT的多模块android项目中面临这个问题。
kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized in MyViewModel
我的模块是
- 应用程序模块
- Viewmodel模块
- 用例模块
- DataSource模块
"应用程序模块">
@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()
}}
"用例模块">
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
}
}
"数据源模块">
interface Feature {
fun doThing()
}
class RealFeature : Feature {
override fun doThing() {
Log.v("Feature", "Doing the thing!")
}
}
依赖项是
MyFragment--->MyViewModel--->MyUseCase--->数据源
我对这个代码做了什么错误,请纠正。
您必须在活动类上方添加注释@AndroidEntryPoint如下所示:
@AndroidEntryPoint类MainActivity:AppCompatActivity(({
除了将所有内容转移到构造函数注入之外,您的RealFeature
也没有被注入,因为您手动实例化它,而不是让Dagger为您构建它。请注意FeatureModule是如何直接调用RealFeature的构造函数并为@Provides
方法返回它的。Dagger会按原样使用这个对象,因为它认为你已经完成了它的所有设置。只有当你让Dagger构建它时,字段注入才有效。
你的功能模块应该是这样的:
@Module
@InstallIn(ApplicationComponent::class)
object FeatureModule {
@Provides
fun feature(realFeature: RealFeature): Feature = realFeature
}
或者带有@Binds
注释:
@Module
@InstallIn(ApplicationComponent::class)
interface FeatureModule {
@Binds
fun feature(realFeature: RealFeature): Feature
}
这也强调了为什么您应该转向构造函数注入;如果使用构造函数注入,就不可能出现这种错误。
代码中的问题是@ViewModelInject
在其他类中不能像@Inject
一样工作。不能在ViewModel中执行字段注入。
你应该做:
class MainViewModel @ViewModelInject constructor(
private val myUseCase: MyUsecase
): ViewModel() {
fun test(){
myUseCase.test()
}
}
考虑对MyUsecase
类采用相同的模式。依赖项应该在构造函数中传递,而不是在类主体中传递@Inject
。这种方式违背了依赖项注入的目的。
首先,我认为RealFeature类中缺少@Inject
,所以Hilt知道如何注入依赖项。其次,如果您想注入到一个不是Hilt支持的入口点的类中,则需要为该类定义自己的入口点。
除了使用@Provides
方法编写的模块外,还需要告诉Hilt如何访问依赖项。
在你的情况下,你应该尝试这样的东西:
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface FeatureInterface {
fun getFeatureClass(): Feature
}
然后,当你想使用它时,写这样的东西:
val featureInterface =
EntryPoints.get(appContext, FeatureInterface::class.java)
val realFeature = featureInterface.getFeatureClass()
你可以在这里找到更多信息:
https://dagger.dev/hilt/entry-points
https://developer.android.com/training/dependency-injection/hilt-android#not-支持的
class MainViewModel @ViewModelInject constructor(private val repository: HomePageRepository,
@Assisted private val savedStateHandle: SavedStateHandle)
: ViewModel(){}
以及如下初始化视图模型的步骤:private lateinit var视图模型:MainViewModelviewModel=ViewModelProviders.of(this(.get(MainViewModel::class.java(
直接使用:
private val mainViewModel:mainViewModel by activityViewModels((
EXplanation:辅助保存状态句柄:将确保如果活动/片段用@Android入口点和视图模型注入进行注释,它将自动注入相应组件活动/应用程序中可用的所有必需的构造函数依赖项,这样我们就不必在片段/活动中初始化视图模型时传递这些参数
确保添加了类路径和插件
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.35'
在Project.gradle 中
apply plugin: 'dagger.hilt.android.plugin'
在app.gradle 中