Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger 2 Named cannot be provided without a @Provides method

Trying to grok Dagger 2 and having an issue with named providers. I have a simple setup as follows:

// 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

When rebuilding my project I am given:

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

I don't understand why adding the Named qualifier doesn't work for me here. If I remove these I can get an instance of SharedPreferences without issue.

Any insight into what I'm doing wrong would be appreciated!

EDIT:

Changes per suggestions with the same results as above.

// 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

like image 863
Matt Sams Avatar asked Mar 24 '16 12:03

Matt Sams


People also ask

How does Dagger 2 work?

Dagger 2 is the first to implement the full stack with generated code. The guiding principle is to generate code that mimics the code that a user might have hand-written to ensure that dependency injection is as simple, traceable and performant as it can be.

How does Dagger dependency injection work?

Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice. Note: Use Hilt for dependency injection on Android.

What is Dagger 2?

Dagger 2 is a compile-time android dependency injection framework that uses Java Specification Request 330 and Annotations. Some of the basic annotations that are used in dagger 2 are: @Module This annotation is used over the class which is used to construct objects and provide the dependencies.

What is Dagger module?

Apart from the @Inject annotation, there's another way to tell Dagger how to provide an instance of a class: the information inside Dagger modules. A Dagger module is a class that is annotated with @Module . There, you can define dependencies with the @Provides annotation. Kotlin Java.


1 Answers

I think I found the problem (at least I checked out your project and it generated dagger classes correctly). If you need to inject fields annotated with @Named or some @Qualifier annotation you have to use this kind of syntax:

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)
    }
}

Notice how @Named / qualifier annotation goes inside @field: (without @ itself).

Idea borrowed from this repo.

like image 166
AndroidEx Avatar answered Oct 30 '22 15:10

AndroidEx