【问题标题】:Inject abstract class (base activity) with HILT使用 HILT 注入抽象类(基础活动)
【发布时间】:2020-08-02 14:39:27
【问题描述】:

我刚刚开始尝试在我非常简单的项目中使用 Hilt。目前一切都在 Dagger2 上,但我想迁移到 Hilt。

我有一个活动:

@AndroidEntryPoint
class MainActivity : BaseActivity() { 
    // SOME STUFF
}

还有一个像这样的 BaseActivity:

abstract class BaseActivity : AppCompatActivity() {
    // SOME STUFF
}

另外,我有一个类使用 baseActivity 来显示一个对话框。例如:

@FragmentScoped
class TestComponentImpl @Inject constructor(
    private val baseActivity: BaseActivity
) : TestComponent {

    override fun displayDialog() {
        MaterialDialog(baseActivity).show { ... 
    }
}

但是,当我尝试编译时,我遇到了这个错误:

如果没有 @Provides-annotated 方法,则无法提供 BaseActivity。

所以,我的问题是:如何构造函数注入抽象类。我尝试了很多东西,但都没有成功,比如在 Hilt 模块中:

    @Provides
    @Singleton
    fun provideBaseActivity(): BaseActivity{
        return BaseActivity() // Of course, it can't work cause it's an abstract class
    } 

或者(就像我对 Dagger 所做的那样):

    @Provides
    @PerActivity
    fun appCompatActivity(baseActivity: BaseActivity) = baseActivity as AppCompatActivity

另外,我只是 Hilt 的初学者,所以也许我错过了什么。我会继续搜索:)

感谢您的宝贵时间和您的回答:)

编辑:

这几天我自己搜索,这似乎有效,但似乎不太好......

@Singleton
@Provides
fun provideBaseActivity(baseActivity: BaseActivity): AppCompatActivity {
    return baseActivity
}

但只有当我这样放置我的 baseActivity 时:

open class BaseActivity Inject constructor() : AppCompatActivity() 

但是,在那之后,如果我尝试像这样在我的 TestComponentImpl 中使用注入的 baseActivity(就像我在 Hilt 之前使用 Dagger 所做的那样):

override fun displayError() {
    Snackbar.make(
        baseActivity.findViewById(android.R.id.content),
        "My error text",
        Snackbar.LENGTH_LONG
    ).apply {
        show()
    }

我还有一个错误:

java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()”

所以我不认为我的 baseActivity 注入做得很好。我正在继续调查;)

【问题讨论】:

    标签: android kotlin dependency-injection dagger-hilt


    【解决方案1】:

    有点 hacky(type-casting),但应该可以工作(未经测试,写在我的头上,所以如果有什么不按预期工作,请随时告诉我):

    创建这样的Module:

    @Module
    @InstallIn(ActivityComponent::class)
    object BaseActivityModule {
    
      @Provides
      fun provideBaseActivity(activity: Activity): BaseActivity {
        check(activity is BaseActivity) { "Every Activity is expected to extend BaseActivity" }
        return activity as BaseActivity  
      }
    }
    

    最后一个演员as BaseActivity 可能是不必要的。 Kotlin 编译器应该处理这个问题。

    【讨论】:

    • 嗨!感谢您的回答。这样做,我得到:如果没有 Inject 构造函数或提供注释的方法,就无法提供 android.app.Activity。另外,我在最后几天自己搜索,这似乎有效(请参阅我的帖子上的编辑)
    • 您是否使用了我的回答中的 @InstallIn(ActivityComponent::class)?这部分很重要
    • 哦,是的,似乎可以与@InstallIn(ActivityComponent::class) 一起使用。抱歉,我尝试使用 @InstallIn(ApplicationComponent::class)。非常感谢 !你能解释一下为什么它使用 ActivityComponent 而不是 ApplicationComponent 吗?因为我知道,如果它在 ApplicationComponent 范围内,则 il 也将在 ActivityComponent 范围内可用(以及组件层次结构中的 fragmentComponent 及以下 --> dagger.dev/hilt/components.html)。我错了吗?
    • 特定XyzComponent“存在”在相关Xyz元素的生命周期中。这意味着此组件提供的依赖项与 Xyz 元素一样长。当Xyz 元素的另一个实例被创建时,XyzComponent 的另一个实例也被生成(以及它的所有直接 依赖项)。 Hilt 足够聪明,可以为其组件提供一些“默认”依赖项。例如。在ActivityComponent 中,您可以使用相关 Activity 作为依赖项(还记得XyzComponentXyz 吗?)。这就是为什么您可以将其用于provideBaseActivity(作为arg)。
    • 当考虑在ApplicationComponent 中构建依赖项时,您不能使用Activity,因为没有与Hilt 可以提供的ApplicationComponent 相关的Activities。只有 Application 实例 (==element) 可以用来构建依赖项。另一方面,如果您想使用Activity,在FragmentComponent 中构建依赖关系,您可以这样做,因为FragmentComponent 在层次结构中低于ActivityComponent(请参阅您提供的链接)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 2021-11-12
    • 2018-07-16
    • 1970-01-01
    相关资源
    最近更新 更多