【问题标题】:Dagger 2 static provider methods in kotlinkotlin 中的 Dagger 2 静态提供程序方法
【发布时间】:2017-12-07 05:35:20
【问题描述】:

在最新版本的 dagger 2 中,其中一项改进是可以使用静态提供方法。就这么简单:

@Provides
static A providesA() {
  return A();
}

我想知道如何在 kotlin 中做到这一点?我试过了

@Module
class AModule {
  companion object {
    @JvmStatic
    @Provides
    fun providesA(): A = A()
  }
}

但我收到错误消息:

@Provides methods can only be present within a @Module or @ProducerModule

我猜伴随对象在这里发生了一些事情,但是我对 Kotlin 还是很陌生,我不确定如何做到这一点。有没有可能?

谢谢!

【问题讨论】:

  • reddit.com/r/androiddev/comments/75rc85/… 上也有关于这个主题的一些讨论,还有第三种选择 - 顶级函数。
  • 这可能是您使用的插件的原因。例如,匕首(Madrappss)。但这仍然有效。
  • @Enciyo 大约 4 年前我问过这个问题。从那时起,匕首已经走了很长一段路,现在支持这一点。当时,它没有......因此问题。

标签: kotlin dagger-2


【解决方案1】:

虽然我认为 zsmb13 的解决方案更好,但我找到了另一个可行的解决方案

@Module
class AModule {
  @Module
  companion object {
    @JvmStatic
    @Provides
    fun providesA(): A = A()
  }

  // add other non-static provides here
}

但是,请注意,将生成两个类:AModule_ProvidesAFactoryAModule_Companion_ProvidesAFactory,而不是一个 AModule_ProvidesAFactory 类,用于带有对象而不是带有伴随对象的类的情况

【讨论】:

  • 实际上,@zsmb13 的解决方案对我不起作用?,你的解决方案。
  • 很高兴它有帮助:D
  • 这也很好,因为 AModule 可以是抽象的
  • 如果 A() 需要一些参数怎么办
  • 如果模块类中同时存在静态提供程序方法和 @Binds 注释方法,则接受的答案将不起作用,而此答案适用于这两种情况。
【解决方案2】:

我现在无法测试它,但我认为这应该可以:

@Module
object AModule {
    @JvmStatic
    @Provides
    fun providesA(): A = A()
}

【讨论】:

  • @Fred,如果它解决了你的问题,你能接受这个答案吗?
  • 但是拥有object 会不会让这个单例类保持太久?刚刚使用内存转储进行了测试,即使在杀死活动并将其从堆中完全删除后,我仍然在内存中有我的 object AModule,这并不是我们想要的......
  • 在 Java 中你拥有静态提供程序方法的类不会保持相同的方式吗?
  • 我不认为这个解决方案效果很好,因为让你的 AModule “对象”而不是“类”会在应用程序周围创建很多单例模块,即使你不需要它们也会存在模块实例,例如,如果您有屏幕范围。一旦你访问你的屏幕,模块单例将被创建并且它永远不会被清理,因为它是“对象”
  • 这个解决方案更好,因为 Jake Wharton 说“不要将companion object 用于模块。使用object。在这种情况下,实例将未被使用,其初始化代码将是被 R8 删除,这些方法将是真正的静态方法,也可以像 Java 一样内联。"。 github.com/google/dagger/issues/900#issuecomment-410041915
【解决方案3】:

https://github.com/google/dagger/issues/900 上似乎得到了 Google 认可的一个很好的解释

具体见:

静态提供可以通过@JvmStatic 实现。我看到有两种情况:

顶级objects

@Module object DataModule {   
  @JvmStatic @Provides fun 
    provideDiskCache() = DiskCache() 
} 

如果你有一个现有的类 模块,事情变得有点奇怪

@Module abstract class DataModule {   
    @Binds abstract fun provideCache(diskCache: DiskCache): Cache

    @Module   
    companion object {
        @JvmStatic @Provides fun provideDiskCache() = DiskCache()   
    } 
} 

其工作方式如下:

伴随对象也必须在底层注释为@Module, kotlin 编译器会将这些静态提供方法复制到 数据模块类。 Dagger 会看到这些并像对待它们一样对待它们 常规静态字段。 Dagger也会在同伴中看到他们 对象,但该“模块”将从匕首获取代码生成但被标记 作为“未使用”。 IDE 会将其标记为 provideDiskCache 方法将被标记为未使用。你可以告诉 IntelliJ 忽略这个 用于通过 quickfix 使用 @Provides 注释的注释

【讨论】:

    【解决方案4】:

    现在Dagger2 (version 2.26) support companion objects in @Module annotated classes in kotlin withthouh @Module and @JvmStatic annotations

    更好地支持 Kotlin 伴侣中的绑定声明 @Module 注解的类的对象。

    将 dagger 依赖项更新为 2.26 版本

    def dagger_version = "2.26"
    //dagger
    implementation "com.google.dagger:dagger:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    
    //If you're using classes in dagger.android you'll also want to include:
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android-support:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"
    

    所以现在你可以使用

    @Module
    class AModule {
    
      companion object {
    
        @Provides
        fun providesA(): A = A()
      }
    
    }
    

    重要提示:很快,在 companion objects@Module 类中添加 @Module引发错误

    注意:为了向后兼容,我们仍然允许 @Module 在 伴随对象和提供方法上的@JvmStatic。然而, 伴随对象上的 @Module 现在是无操作的,并且它的所有 属性(例如“包含”)将被忽略。 In future releases, we will make it an error to use @Module on a companion object.

    【讨论】:

    • 应该是公认的答案“D,其他都不错,但这是最新的
    【解决方案5】:

    对于仅静态方法,我喜欢zsmb13的解决方案。

    但是,我来到这里是因为我想将@Provides@Binds 合并到一个模块中。 这不是直接可行的,而是使用两个嵌套模块(正如Omar Al Halabi 指出的那样)。

    我采用了一种稍微不同的方法来组合@Provides@Binds

    @Module(includes = [MyModule.Bindings::class])
    object MyModule {
        @Module
        interface Bindings {
            @Binds
            fun bindA(a: AImpl): A
        }
    
        @Provides
        @JvmStatic
        fun provideB(): B = BImpl()
    }
    

    区别在于:

    • 外部模块是提供静态功能的对象。这可以避免使用无意的companion object
    • 内部模块保存抽象绑定。我可以在这里使用一个接口,它在类和函数中都保留了abstract 修饰符。
    • 外部模块包含内部模块,因此我不必在其他地方包含内部模块。

    【讨论】:

      猜你喜欢
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多