【问题标题】:Inject class in to view component with Hilt使用 Hilt 注入类以查看组件
【发布时间】:2020-09-28 19:30:44
【问题描述】:

我有一个自定义 WebView,我添加到我的布局 xml:

<my.company.ui.ExtendedWebView />

它扩展了原生的 WebView:

class ExtendedWebView @JvmOverloads constructor(context: Context, 
    attrs: AttributeSet? = null,  defStyle: Int = 0) 
    : WebView(context, attrs, defStyle) {
// ...
}

如何使用 Hilt 将 @Singelton 类注入到上面的类中?属性注入?我应该如何注释类?

【问题讨论】:

    标签: android dagger-2 dagger-hilt


    【解决方案1】:

    我发现@AndroidEntryPoint 注释需要在视图、片段(如果在片段中)和活动上。因为注解。

    因此,假设您的 DI 设置如下:

    /* CONTENTS OF com.org.app.di/dependencyModule.kt */
    @Module
    @InstallIn(ViewComponent::class)
    object DependencyModule {
        @Provides
        fun provideDependency(@ApplicationContext context: Context): DependencyType
                = DependencyInstance(context)
    }
    

    我的应用程序设置正确:

    @HiltAndroidApp
    class SuperAwesomeApplication : Application()
    /* Remember to reference this is the manifest file, under the name attricbute! */
    

    现在,如果我有一个带有注入依赖项的视图:

    @AndroidEntryPoint
    class SuperAwesomeView(context: Context, attrs: AttributeSet) : View(context, attrs) {
        @Inject
        lateinit var dependency: DependencyType
        ...
    

    我会得到错误:

    ...
    Caused by: java.lang.IllegalStateException: class com.app.org.ui.view.SuperAwesomeView, Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity.
    ...
    

    所以我将@AndroidEntryPoint注解添加到包含视图的Fragment中:

    @AndroidEntryPoint
    class SuperAwesomeFragment : Fragment() {
    ...
    

    然后我们遇到下一个错误:

     Caused by: java.lang.IllegalStateException: Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.org.ui.SuperAwesomeActivity
    

    所以我了解到注释需要一直冒泡,从 View 到(如果在 Fragment 中)Fragment,再到 Activity:

    @AndroidEntryPoint
    class SuperAwesomeActivity : AppCompatActivity() {
    ...
    

    【讨论】:

    • 是的,我得出了同样的结论。接受这个
    【解决方案2】:

    假设您的 singleton class 目前看起来像这样:

    class ExampleSingletonClass( //... some dependencies) {
         //.. some other stuff
    }
    

    要使其成为单例,请将其更改为:

    @Singleton
    class ExampleSingletonClass @Inject constructor( //... some dependencies) {
         //.. some other stuff
    }
    

    然后,将其注入到您的 ExtendedWebView 中:

    class ExtendedWebView @JvmOverloads @Inject constructor(
        context: Context, 
        attrs: AttributeSet? = null,  
        defStyle: Int = 0,
        private val exampleSingleton: ExampleSingletonClass // your singleton, doesn't need to be private.
       ) : WebView(context, attrs, defStyle) {
    // ...
    }
    

    你在这里不需要任何@AndroidEntryPoint,但你的Fragment / Activity需要@AndroidEntryPoint

    【讨论】:

    • 谢谢。如果我这样做,我会得到Types may only contain one @Inject constructor。我应该删除默认参数吗?
    • @filur 要么删除默认参数,要么使用默认参数创建第二个构造函数并让它指向第一个构造函数。在第二个构造函数上也执行@Inject。可以参考this
    • 明白了。您能否发布一个使用 2 构造函数方法的示例?
    • @filur 很抱歉,但我看到这很遗憾是不可能的(至少我是这样尝试的)。 Kotlin 无法区分两个构造函数,因为一个有默认值,另一个没有。它说Conflicting overloads。我的解决方案:如果可以,只需删除默认参数,否则,您必须忍受警告Types may only contain one @Inject constructor
    • 谢谢,我想在这种情况下删除它们不会受到伤害,因为框架希望设置它们。
    猜你喜欢
    • 2021-04-16
    • 2021-08-30
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多