当前位置: 首页 > 知识库问答 >
问题:

超级片段或视图模型中的希尔特场注入

毋琪
2023-03-14

我正在使用Dagger-Hilt在我的Android项目中进行依赖注入,现在我遇到了这样的情况,我有一个基本的抽象片段

abstract class BaseViewModel constructor(
    val api: FakeApi,
) : ViewModel() {
    
    //...
    
}

在这里,我有一个依赖项,即FakeApi。我正在尝试做的是将FakeApi注入到BaseViewModel中,以便在BaseViewModel及其所有子项中可用。

    < li >我尝试的第一种方法是使用构造函数注入,并将其注入到子节点,然后使用构造函数将其传递给超级节点。
@HiltViewModel
class TaskViewModel @Inject constructor(
    api: FakeApi
) : BaseViewModel(api){

}

这种方法工作得很好,但是我不需要将依赖关系从传递到超级类,我需要将FakeApi自动注入BaseViewModel中而不必传递它,因为我有三个抽象级别(还有一个类继承自TaskViewModel)所以我必须传递两次。

  • 第二种方法是使用字段注入,如下所示
abstract class BaseViewModel: ViewModel() {
    @Inject
    lateinit var api: FakeApi
    //...
}
@HiltViewModel
class TaskViewModel @Inject constructor(): BaseViewModel() {
    
}

这种方法对我不起作用,没有注入< code>FakeApi,我得到了一个< code >异常

kotlin.UninitializedPropertyAccessException: lateinit property api has not been initialized
  • 为什么现场注射对我不起作用?
  • 有没有办法为超级类使用构造函数注入,而不是从传递依赖项?

共有2个答案

孙宏壮
2023-03-14

我测试了一下,我看到基类中的场注入仍然适用于 Hilt 2.35。我不能像你一样得到错误,所以也许你可以尝试更改希尔特版本或检查你如何提供FakeApi

abstract class BaseViewModel : ViewModel() {

    @Inject
    protected lateinit var fakeApi: FakeApi
}

FakeApi

// Inject constructor also working
class FakeApi {

    fun doSomeThing() {
        Log.i("TAG", "do something")
    }
}

主视图模型

@HiltViewModel
class MainViewModel @Inject constructor() : BaseViewModel() {

    // from activity, when I call this function, the logcat print normally 
    fun doSomeThing() {
        fakeApi.doSomeThing()
    }
}

应用模块

@Module
@InstallIn(SingletonComponent::class)
class AppModule {

    @Provides
    fun provideAPI(
    ): FakeApi {
        return FakeApi()
    }
}

https://github.com/PhanVanLinh/AndroidHiltInjectInBaseClass

韩鸿波
2023-03-14

多亏了这个 Github 问题,我发现问题是你不能在 ViewModel 构造函数初始化期间使用字段注入的属性,但在构造函数(包括所有属性直接初始化)初始化后仍然使用它。

Dagger首先完成构造器注入过程,然后进行现场注入过程。这就是为什么在构造函数注入完成之前不能使用字段注入的原因。

abstract class BaseViewModel : ViewModel() {

    @Inject
    protected lateinit var fakeApi: FakeApi

    val temp = fakeApi.doSomething() // Don't use it in direct property declaration

    init {
        fakeApi.doSomething() // Don't use it in the init block
    }
}
kotlin prettyprint-override">abstract class BaseViewModel : ViewModel() {

    @Inject
    protected lateinit var fakeApi: FakeApi

    val temp: Any
        get() = fakeApi.doSomething() // Use property getter

    fun doSomething(){
        fakeApi.doSomething() // Use it after constructor initialization
    }
}

或者,您可以使用lazy</code>的<code>来声明属性。

 类似资料:
  • 我试图使用hilt将viewmodel注入片段,为此我创建了两个模块,一个用于我的网络组件,另一个用于角色的viewmodel。 网络模块安装在单例组件中,我需要将字符模块安装在FragmentComponent中,以通过“by view模型()”获取视图模型 我的活动和片段用“@AndroidEntryPoint”注释,我的应用程序用“@HiltAndroidApp”注释。我的模块是: 我的视图

  • 我正在使用更新动作栏中的标题 共享视图模型 主要活动观察者 使用下面的代码似乎会在< code>Fragment中创建新的实例(在调试器中检查): 但似乎是这样的 文章参考 这是应该这样做还是我做错了什么? 谢谢你!

  • 在过去,Google提供了碎片类(这里我也问过我们什么时候应该使用它)。 现在,Android 4.4有了一个新的框架类,叫做“场景”。 根据我所读到的(和在课堂上看的,例如这里),它应该帮助你在状态之间的动画和转换。 这个有官方的样品吗? 是否有兼容库,可以在4.4之前的版本上使用它?

  • 如何注入抽象类我有一个抽象类 我尝试使用< code>@Module和< code>@Binds注释来初始化该类的对象。但这并不能创建并抛出一个错误。 但这给出了错误。我犯了什么错误?请您告诉我如何为抽象类创建。我们如何注入抽象类?从文档中,它说。有时,不能注入构造函数。发生这种情况可能有多种原因。例如,不能构造函数注入接口。也不能构造函数注入不属于的类型,例如外部库中的类。在这些情况下,您可以使

  • 我正在写一个使用片段的简单示例。在主体活动中,有两个片段。第一个片段有一些文本视图,第二个片段有一些按钮。当用户点击textview时,文本打开按钮将被更改。 activity_main.xml mainactivity.java contentFrag.java 我没有编写控制按钮的操作,只是生成onclick事件。但是,我弄错了。请帮助我修复错误,并继续完成我的任务。

  • 我有一个ViewPagerContainer片段,在应用程序启动时加载。ViewPagerContainer片段将两个选项卡(选项卡A和选项卡B)添加到操作栏。选项卡B有两个项目的列表视图。 我所做的:我在选项卡B片段中的列表视图项上附加了一个click listener,这样当用户单击一个项时,它会在第一个片段(即选项卡B下)内打开另一个片段(子片段)。 我陷入困境的地方:当用户按下后退按钮时,