HILT:lateinit属性存储库尚未在ViewModel中初始化



我在使用HILT的多模块android项目中面临这个问题。

kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized in MyViewModel

我的模块是

  1. 应用程序模块
  2. Viewmodel模块
  3. 用例模块
  4. 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 中