kotlin中的Dagger 2静态提供程序方法

Fre*_*red 46 kotlin dagger-2

对于最近版本的匕首2,所做的改进之一是具有静态提供方法的可能性.简单地说:

@Provides
static A providesA() {
  return A();
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何在kotlin做这件事?我试过了

@Module
class AModule {
  companion object {
    @JvmStatic
    @Provides
    fun providesA(): A = A()
  }
}
Run Code Online (Sandbox Code Playgroud)

但我收到错误消息:

@Provides methods can only be present within a @Module or @ProducerModule
Run Code Online (Sandbox Code Playgroud)

我猜这里有同伴对象,但是我对Kotlin很新,我不确定如何做到这一点.它甚至可能吗?

谢谢!

Oma*_*abi 51

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

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

  // add other non-static provides here
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果模块类中同时存在静态提供程序方法和"@Binds"注释方法,则接受的答案将不起作用,而此答案适用于这两种情况. (11认同)
  • 实际上,@ zsmb13的解决方案对我不起作用,您的对我来说无效。 (2认同)
  • 这也很好,因为AModule可以是抽象的 (2认同)

zsm*_*b13 40

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

@Module
object AModule {
    @JvmStatic
    @Provides
    fun providesA(): A = A()
}
Run Code Online (Sandbox Code Playgroud)

  • 但是有了"对象",它会不会让这个单例类太久了?刚刚使用内存转储测试,甚至在杀死活动并将其从堆中完全删除后,我仍然在内存中存在"对象AModule",这不是我们想要的...... (4认同)
  • 我不认为这个解决方案效果很好,因为使你的AModule"对象"不是"类"会在应用程序周围创建很多单例模块,即使你不再需要这个模块实例它们也会存在,例如你有屏幕范围.一旦你访问你的屏幕,将创建模块单例,它将永远不会被清理,因为它是"对象" (3认同)
  • 这个解决方案更好,因为 Jake Wharton 说“_不要对模块使用 `companion object`。使用 `object`。在这种情况下,实例将不被使用,它的初始化代码将被 R8 删除,方法将是真正的静态也可以像 Java._ 一样内联。https://github.com/google/dagger/issues/900#issuecomment-410041915 (2认同)

Pav*_*ngh 16

现在Dagger2(2.26 版)支持kotlincompanion objects中带@Module注释的类,带有 @Module 和 @JvmStatic 注释

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

将 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"
Run Code Online (Sandbox Code Playgroud)

所以现在你可以使用

@Module
class AModule {

  companion object {

    @Provides
    fun providesA(): A = A()
  }

}
Run Code Online (Sandbox Code Playgroud)

重要提示:不久,加上@Modulecompanion objects@Module班会引发错误

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

  • 应该是公认的答案“D,其他都很好,但这是最新的 (2认同)

sop*_*hia 12

似乎是谷歌批准的一个很好的解释是https://github.com/google/dagger/issues/900

具体来说,请看:

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

顶级object

@Module object DataModule {   
  @JvmStatic @Provides fun 
    provideDiskCache() = DiskCache() 
} 
Run Code Online (Sandbox Code Playgroud)

如果你有一个现有的类模块,事情会有点怪异

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

    @Module   
    companion object {
        @JvmStatic @Provides fun provideDiskCache() = DiskCache()   
    } 
} 
Run Code Online (Sandbox Code Playgroud)

这种方式的工作方式如下:

伴随对象也必须在引擎盖下注释为@Module,kotlin编译器会将这些静态提供方法复制到DataModule类中.匕首会看到那些并将它们视为常规静态场.Dagger也会在伴侣对象中看到它们,但是"模块"将从匕首获得代码,但被标记为"未使用".IDE将这样标记,因为provideDiskCache方法将被标记为未使用.您可以告诉IntelliJ忽略这个注释,注释使用@Provides通过quickfix注释


Pet*_*r F 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()
}
Run Code Online (Sandbox Code Playgroud)

区别在于:

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