匕首柄
2.42
我正在尝试使用惰性匕首注入来提供此类。
class AlgoliaAnalyticsProvider @Inject constructor(
private val clientInsights: Lazy<ClientInsights>,
private val coroutineDispatcherProvider: CoroutineDispatcherProvider
)
在我的 AppModule 中,我有以下内容:
@Singleton
@Provides
fun provideClientInsights(remoteConfigProvider: RemoteConfigProvider): Lazy<ClientInsights> {
return lazy { ClientInsights(
ApplicationID(BuildConfig.ALGOLIA_APP_ID),
APIKey(remoteConfigProvider.keyAlgoliaApiKey)
)}
}
我在通过
AlgoliaAnalyticsProvider
的地方也有这个
@Singleton
@Provides
fun provideAnalyticsProvider(
firebaseAnalyticsProvider: FirebaseAnalyticsProvider,
crashlyticsUserPropertiesProvider: CrashlyticsUserPropertiesProvider,
caMPAnalyticsProvider: CaMPAnalyticsProvider,
algoliaAnalyticsProvider: AlgoliaAnalyticsProvider
) = AnalyticsProvider(
listOf(
firebaseAnalyticsProvider,
crashlyticsUserPropertiesProvider,
algoliaAnalyticsProvider
)
)
我不断收到此错误:
error: [Dagger/MissingBinding] kotlin.Lazy<? extends com.algolia.search.client.ClientInsights> cannot be provided without an @Provides-annotated method.
public abstract static class SingletonC implements CDSApplication_GeneratedInjector,
^
kotlin.Lazy<? extends com.algolia.search.client.ClientInsights> is injected at
com.centraldepartment.app.analytics.provider.AlgoliaAnalyticsProvider(clientInsights, …)
com.centraldepartment.app.analytics.provider.AlgoliaAnalyticsProvider is injected at
com.centraldepartment.app.analytics.AnalyticsModule.provideAnalyticsProvider(…, algoliaAnalyticsProvider, …)
但是如果我注释掉下面的代码,它似乎可以工作:
@Singleton
@Provides
fun provideAnalyticsProvider(
firebaseAnalyticsProvider: FirebaseAnalyticsProvider,
crashlyticsUserPropertiesProvider: CrashlyticsUserPropertiesProvider,
caMPAnalyticsProvider: CaMPAnalyticsProvider,
// algoliaAnalyticsProvider: AlgoliaAnalyticsProvider
) = AnalyticsProvider(
listOf(
firebaseAnalyticsProvider,
crashlyticsUserPropertiesProvider,
// algoliaAnalyticsProvider
)
)
您需要更改 AlgoliaAnalyticsProvider 构造函数以接受
Lazy<@JvmSuppressWildcards ClientInsights>
而不是 Lazy<ClientInsights>
。这并不是关于 Lazy 的任何具体内容,只是它涉及一个 @Provides
方法,返回 Kotlin 中泛型的内容。
Java 和 Kotlin 中的泛型很棘手,如 Kotlin 泛型文档中的 “方差”部分所述。 Kotlin 提供
in
和 out
作为“方差注释”,比 Java 提供的 通用通配符 (Lazy<? extends Foo>
) 更有助于推理。然而,即使没有这些方差注释,泛型也会造成足够的互操作问题,以至于 Kotlin 的默认互操作行为默认添加通配符:
为了使 Kotlin API 在 Java 中工作,当
作为参数出现时,编译器将生成为Box<Super>
(对于协变定义的Box<? extends Super>
)(或Box
对于逆变定义的Foo<? super Bar>
Foo
)。当它是返回值时,不会生成通配符,因为否则 Java 客户端将不得不处理它们(这违背了常见的 Java 编码风格)。
这对于您的使用来说是没问题的 -
Lazy<? extends ClientInsights>
完全可以让您在 AlgoliaAnalyticsProvider 中获得所需的 ClientInsights 或子类 - 但如您的错误消息所示,Dagger 未能成功搜索 kotlin.Lazy<? extends ClientInsights>
的绑定并且不会接受kotlin.Lazy<ClientInsights>
的绑定。要抑制 Kotlin 的默认行为,您需要在上面的同一互操作页面上应用解决方法:将 @JvmSuppressWildcards
添加到您的参数中。然后,您的调用站点泛型将与您的 @Provides
返回值完全匹配,并且 Dagger 将正确应用您的绑定。
通配符困难是 Dagger 使用 Kotlin 时的一个已知痛点,如 开放问题 google/dagger#2586 以及引发它的评论。文档中有一条可见的警告消息,但仅在多重绑定页面上,因为多重绑定创建的集合也面临这种危险。
需要明确的是,上面的答案是关于 Kotlin 内置函数
lazy
。另外,Dagger 有一个名为 Lazy 的内置包装类,它的工作方式与 Provider 非常相似,但只会在每个 Lazy 实例第一次调用 @Provides
方法或 @Inject
构造函数。对于图表中的任何绑定 T,Dagger 将自动使 Provider<T>
、dagger.Lazy<T>
和 Provider<dagger.Lazy<T>>
可用。
这实际上可能更符合您的需求:您的
@Provides
方法将直接返回 ClientInsights,然后您可以将其注入作为您选择的 ClientInsights、Provider<ClientInsights>
或 Lazy<ClientInsights>
;在内部,Dagger 还可以避免创建 Provider<kotlin.Lazy<ClientInsights>>
,因为 Dagger 可以直接返回用于强制执行您添加的 @Singleton
注释的相同内部 DoubleCheck 实现。但是,如果您不想要能够直接注入 ClientInsights 而只注入
Lazy<@JvmSuppressWildcards ClientInsights>
,那么简单地添加注释可能是最好的方法。
就我而言,问题在于没有使用正确的导入。
正确:
import dagger.Lazy