【问题标题】:Dagger 2 Named cannot be provided without a @Provides method如果没有 @Provides 方法,则无法提供 Dagger 2 Named
【发布时间】:2016-07-12 00:29:27
【问题描述】:

尝试深入了解 Dagger 2 并遇到命名提供程序的问题。我有一个简单的设置如下:

// Module
@Module
class AppModule(private val app: App) {
    @Provides @AppScope fun providesApp() = app

    @Provides @AppScope fun provideSharedPreferences(app: App) = PreferenceManager.getDefaultSharedPreferences(app)

    @Provides @AppScope @Named("Uri1") fun providesUri1() = Uri.Builder().scheme("https").authority("authory1").build()

    @Provides @AppScope @Named("Uri2") fun providesUri2() = Uri.Builder().scheme("https").authority("authory2").build()
}

// Component
@AppScope
@Component(modules = arrayOf(AppModule::class))
interface AppComponent {
    fun inject(target: MainActivity)
}

// MainActivity
@Inject @AppScope lateinit var preferences: SharedPreferences
@Inject @AppScope @Named("Uri1") lateinit var uri1: Uri
@Inject @AppScope @Named("Uri2") lateinit var uri2: Uri

当我重建我的项目时:

Error:Gradle: android.net.Uri cannot be provided without an @Provides- or @Produces-annotated method.

我不明白为什么在这里添加 Named 限定符对我不起作用。如果我删除这些,我可以毫无问题地获得 SharedPreferences 的实例。

任何关于我做错了什么的见解将不胜感激!

编辑:

根据建议进行更改,结果与上述相同。

// New module
@Module
class AppModule(private val app: App) {
    @Provides @AppScope fun providesApp() = app

    @Provides @AppScope fun provideSharedPreferences(app: App) = PreferenceManager.getDefaultSharedPreferences(app)

    @Provides @AppScope @Tag("Uri1") fun providesUri1(): Uri = Uri.Builder().scheme("https").authority("authority1").build()

    @Provides @AppScope @Tag("Uri2") fun providesUri2(): Uri = Uri.Builder().scheme("https").authority("authority2").build()
}

// Tag annotation
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class Tag(val tag: String = "")

// MainActivity
@Inject @AppScope lateinit var preferences: SharedPreferences
@Inject @AppScope @Tag("Uri1") lateinit var uri1: Uri
@Inject @AppScope @Tag("Uri2") lateinit var uri2: Uri

Project Repo @ Github

【问题讨论】:

  • 嗯,您的设置看起来不错。你能试试两件事吗? 1) 为您的provides* 方法显式指定返回类型为Uri。 2)尝试使用限定符注解(自定义注解本身用@Qualifier注解并以与@Named相同的方式使用)而不是@Named来区分uri。
  • @AndroidEx 根据建议进行了更改,请参阅编辑后的帖子。到目前为止结果没有区别!
  • 我以前没有在字段上看到范围。尝试删除@Inject @AppScope @Tag("Uri1") lateinit var uri1: Uri 中的范围,否则我必须同意,它看起来不错
  • 我同意大卫的范围。另外,您不需要设置保留,因为它在 kotlin 中默认为运行时,为您节省了一行。我也从未使用过带有附加字段的限定符注释,例如您可以创建@Uri1@Uri2 注释并使用它们...
  • 感谢 David 和 AndroidEx 的建议。不幸的是,同样的问题仍然存在。如果更完整的上下文有帮助,我已经在 GitHub 上添加了测试项目存储库的链接:github.com/deadpixelsociety/sandbox。谢谢!

标签: android dependency-injection kotlin dagger-2


【解决方案1】:

我想我发现了问题(至少我检查了你的项目并且它正确地生成了匕首类)。如果您需要注入带有@Named 或一些@Qualifier 注释的字段,则必须使用这种语法:

class MainActivity : AppCompatActivity() {
    @Inject lateinit var preferences: SharedPreferences
    @Inject @field:[Named ("Uri1")] lateinit var uri1: Uri // for @Named annotation or...
    @Inject @field:Uri2 lateinit var uri2: Uri // ...for @Qualifier annotation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        app().component.inject(this)

        println(uri1)
        println(uri2)
    }
}

注意@Named / 限定符注释如何进入@field:(没有@ 本身)。

repo借来的想法。

【讨论】:

  • 你成功了!在你说这完全有道理之后。感谢您的努力!
  • 当前语法是@Inject @AppScope @field:[Named ("Uri1")] lateinit var uri1: Uri 而不是@Inject @AppScope @field:[Uri1] lateinit var uri1: Uri
  • @NitroG42 我认为您描述了一种不同的情况,如果@Uri1 被注释为@Qualifier,那么我的语法是正确的。这只是一个例子,我没有具体说明我是使用@Qualifier还是@Named注解,这个实现留给读者。
  • @AppScope 注释在我的情况下是不必要的
  • @AlexBerdnikov 这与默认的注解目标顺序kotlinlang.org/docs/…有关。因此,如果我们不明确指定注解目标,则目标将是property。这不是 Java 或 Dagger 2 可以看到或关心的事情,并且公共字段本身(在 Java 术语中)没有注释。您可以使用 Intellij 的“显示 Kotlin 字节码”->“反编译”查看它解析的字节码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 2020-05-16
  • 1970-01-01
  • 1970-01-01
  • 2022-10-24
  • 2019-02-26
相关资源
最近更新 更多