Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger2 : How to use @Provides and @Binds in same module

People also ask

What is the difference between @provides and @binds statement?

Because @Binds methods are just a method declaration, they are expressed as abstract methods — no implementation is ever created and nothing is ever invoked. On the other hand, a @Provides method does have an implementation and will be invoked.

What does @binds do dagger?

@Binds prevents Dagger from having to codegen and keep a separate Factory/Provider for the object, since Java doesn't give Dagger access to know that the implementation is as simple as it is.

What is ContributesAndroidInjector?

Annotation Type ContributesAndroidInjectorThe injector is implemented with a Subcomponent and will be a child of the Module 's component. This annotation must be applied to an abstract method in a Module that returns a concrete Android framework type (e.g. FooActivity , BarFragment , MyService , etc).


@Binds and @ContributesAndroidInjector methods must be abstract, because they don't have method bodies. That means that they must go on an interface or abstract class. @Provides methods may be static, which means they can go on abstract classes and Java-8-compiled interfaces, but non-static ("instance") @Provides methods don't work on abstract classes. This is explicitly listed in the Dagger FAQ, under the sections "Why can’t @Binds and instance @Provides methods go in the same module?" and "What do I do instead?".

If your @Provides method doesn't use instance state, you can mark it static, and it can go onto an abstract class adjacent to your @Binds methods. If not, consider putting the bindings like @Binds and @ContributesAndroidInjector into a separate class--possibly a static nested class--and including that using the includes attribute on Dagger's @Module annotation.


A little addition to Jeff's solution above:

you may create inner interface instead of static inner class, like this:

@Module(includes = AppModule.BindsModule.class)
public class AppModule {
    // usual non-static @Provides
    @Provides
    @Singleton
    Checkout provideCheckout(Billing billing, Products products) {
        return Checkout.forApplication(billing, products);
    }
    // interface with @Binds
    @Module
    public interface BindsModule {
        @Binds
        ISettings bindSettings(Settings settings);
    }
}

If you are in kotlin world, another alternative is to leverage companion object

@Module
abstract class MyDaggerModule {

    @Binds
    abstract fun provideSomething(somethingImpl: SomethingImpl): Something

    companion object {

        @Provides
        fun provideAnotherThing(): AnotherThing {
            return AnotherThing()
        }
    }
}