使用Dagger 2提供功能依赖性

时间:2018-07-18 15:47:38

标签: android dependency-injection kotlin functional-programming dagger-2

我想使用Dagger 2作为依赖提供一个功能

@Module
class DatabaseModule {

    @Provides
    @Singleton
    fun provideDatabase(application: Application, betaFilter: (BetaFilterable) -> Boolean): Database {
        return Database(application, BuildConfig.VERSION_CODE, betaFilter)
    }

    @Provides
    @Suppress("ConstantConditionIf")
    fun provideBetaFiler(): (BetaFilterable) -> Boolean {
        return if (BuildConfig.FLAVOR_audience == "regular") {
            { it.betaOnly.not() }
        } else {
            { true }
        }
    }

}

不幸的是,它似乎不起作用:

[dagger.android.AndroidInjector.inject(T)] kotlin.jvm.functions.Function1<? 
super com.app.data.BetaFilterable,java.lang.Boolean> 
cannot be provided without an @Provides-annotated method.

我在这里想念什么?

3 个答案:

答案 0 :(得分:4)

是的,这可以在Kotlin中完成。

  

您需要在注射位置添加@JvmSuppressWildcards以确保   签名匹配。   (source

我编写了以下内容进行验证:

import dagger.Component
import dagger.Module
import dagger.Provides
import javax.inject.Singleton

class G constructor(val function: Function1<Int, Boolean>)

@Singleton
@Module
class ModuleB {
    @Provides
    fun intToBoolean(): (Int) -> Boolean {
        return { it == 2 }
    }
    @JvmSuppressWildcards
    @Provides fun g(intToBoolean: (Int) -> Boolean): G {
        return G(intToBoolean)
    }
}

@Singleton
@Component(modules = [ModuleB::class])
interface ComponentB {
    fun g(): G
}

val componentB = DaggerComponentB.create()
val g = componentB.g()
println(g.function(2)) // true
println(g.function(3)) // false

答案 1 :(得分:3)

它不起作用,因为为了允许调用具有超类型的函数代替lambda(可以使用(Any) -> Boolean(BetaFilterable) -> Boolean),因为函数将参数作为参数生成字节码以允许这个。

以下代码:

object Thing

fun provide(): (Thing) -> Boolean {
    TODO()
}

fun requires(func: (Thing) -> Boolean) {
    TODO()
}

产生以下签名:

  

签名()Lkotlin/jvm/functions/Function1<LThing;Ljava/lang/Boolean;>;

     

声明:kotlin.jvm.functions.Function1<Thing, java.lang.Boolean> provide()

     

签名(Lkotlin/jvm/functions/Function1<-LThing;Ljava/lang/Boolean;>;)V

     

声明:void requires(kotlin.jvm.functions.Function1<? super Thing, java.lang.Boolean>)

-LThing? super Thing)和LThingThing)之间的细微差别使Dagger的类型不兼容。

我认为无法实现此目的,您需要定义一个单独的接口,该接口不具有与? super相同的? extends / Function1属性。

答案 2 :(得分:2)

正如Kiskae的回答中指出的那样,不可能使用kotlin来完成这项工作。您可以使用Java来使其工作:

@Module
public class DatabaseModuleJava {

    @Provides
    @Singleton
    public Database provideDatabase(Application application, Function1<BetaFilterable, Boolean> betaFilter) {
        return new Database(application, BuildConfig.VERSION_CODE, betaFilter);
    }

    @Provides
    @Singleton
    @SuppressWarnings("ConstantConditions")
    public Function1<BetaFilterable, Boolean> provideBetaFiler() {
        if (BuildConfig.FLAVOR_audience.equals("regular")) {
            return betaFilterable -> !betaFilterable.getBetaOnly();
        } else {
            return betaFilterable -> true;
        }
    }

}