Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Provides and @Binds methods in same class Kotlin

After dagger 2.11 we can use a @Binds annotation and mark our Module as abstract in this case which is more efficient than a concrete.

If my Module has both @Provides and @Binds methods, I have two options :

  1. Simplest would be to mark your @Provides instance methods as static.

  2. If it is necessary to keep them as instance methods, then you can split your module into two and extract out all the @Binds methods into an abstract Module.

The second option works fine in Java and Kotlin but the first option works fine in Java but I don't know how to implement the same in Kotlin. If I move @Provides method to Companion object it throw Error:(30, 1) error: @Provides methods can only be present within a @Module or @ProducerModule. How can do this in Kotlin.

Second Option:(Working)

ApplicationModule.kt

@Module(includes = [ApplicationModule.Declarations::class])
abstract class ApplicationModule {
    @Module
    internal interface Declarations {
        @Binds
        fun bindContext(application: Application): Context
    }

    @Provides
    @Singleton
    fun provideMvpStarterService(): MvpStarterService {
        return MvpStarterServiceFactory.makeStarterService()
    }
}

First Option:(Not working)

ApplicationModule.kt

@Module
abstract class ApplicationModule {
    //expose Application as an injectable context
    @Binds
    internal abstract fun bindContext(application: Application): Context

    companion object {
        @JvmStatic
        @Provides
        @Singleton
        fun provideMvpStarterService(): MvpStarterService {
            return MvpStarterServiceFactory.makeStarterService()
        }
    }
}

Generated Java file for first option:

@kotlin.Metadata(mv = {1, 1, 9}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\b\'\u0018\u0000 \b2\u00020\u0001:\u0001\bB\u0005\u00a2\u0006\u0002\u0010\u0002J\u0015\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u0006H!\u00a2\u0006\u0002\b\u0007\u00a8\u0006\t"}, d2 = {"Lio/mywebsie/di/ApplicationModule;", "", "()V", "bindContext", "Landroid/content/Context;", "application", "Landroid/app/Application;", "bindContext$app_debug", "Companion", "app_debug"})
@dagger.Module()
public abstract class ApplicationModule {
    public static final io.mywebsie.di.ApplicationModule.Companion Companion = null;

    @org.jetbrains.annotations.NotNull()
    @dagger.Binds()
    public abstract android.content.Context bindContext$app_debug(@org.jetbrains.annotations.NotNull()
    android.app.Application application);

    public ApplicationModule() {
        super();
    }

    @org.jetbrains.annotations.NotNull()
    @javax.inject.Singleton()
    @dagger.Provides()
    public static final io.mywebsie.data.remote.MvpStarterService provideMvpStarterService() {
        return null;
    }

    @kotlin.Metadata(mv = {1, 1, 9}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002\u00a2\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007\u00a8\u0006\u0005"}, d2 = {"Lio/mywebsie/di/ApplicationModule$Companion;", "", "()V", "provideMvpStarterService", "Lio/mywebsie/data/remote/MvpStarterService;", "app_debug"})
    public static final class Companion {

        @org.jetbrains.annotations.NotNull()
        @javax.inject.Singleton()
        @dagger.Provides()
        public final io.mywebsie.data.remote.MvpStarterService provideMvpStarterService() {
            return null;
        }

        private Companion() {
            super();
        }
    }
}

Update:

Thanks to @David Medenjak the link you provided in comment made everything clear I came across two ways to achieve the first option.

Updated code:

First Option:(Working)

ApplicationModule.kt

@Module(includes = [ApplicationModule.AModule::class])
abstract class ApplicationModule {

    @Binds
    abstract fun bindContext(application: Application): Context

    @Module
    object AModule {
        @JvmStatic
        @Provides
        @Singleton
        fun provideMvpStarterService(): MvpStarterService {
            return MvpStarterServiceFactory.makeStarterService()
        }
    }
}

or

@Module
abstract class ApplicationModule {
    @Binds
    abstract fun bindContext(application: Application): Context

    @Module
    companion object {
        @Provides
        @Singleton
        fun provideMvpStarterService(): MvpStarterService {
            return MvpStarterServiceFactory.makeStarterService()
        }
    }
}

Both works just fine but for some reason the first option does not look appealing to me so I prefer the second option.

like image 847
Sai Avatar asked Jan 22 '18 17:01

Sai


1 Answers

Here's an example code to demonstrate how to use Binds and Provides annotated methods in a single Kotlin class:

@Module
abstract class MessagesPresentationModule {

    @Module
    companion object {
        const val MESSAGES = 0x00

        @JvmStatic
        @Provides
        fun provideRecyclerAdapter(
            itemComparator: DisplayItemComperator,
            factoryMap: Map<Int, ViewHolderFactory>,
            binderMap: Map<Int, ViewHolderBinder>,
            androidPreconditions: AndroidPreconditions
        ): RecyclerViewAdapter {
            return RecyclerViewAdapter(
                itemComperator = itemComparator,
                viewHolderFactoryMap = factoryMap,
                viewBinderFactoryMap = binderMap,
                androidPreconditions = androidPreconditions
            )
        }
    }

    @Binds
    @IntoMap
    @IntKey(MESSAGES)
    internal abstract fun provideMessagesViewModelFactory(factory: MessagesViewHolder.MessageViewHolderFactory): ViewHolderFactory

    @Binds
    @IntoMap
    @IntKey(MESSAGES)
    internal abstract fun provideMessagesViewHolderBinder(binder: MessagesViewHolder.MessagesViewHolderBinder): ViewHolderBinder
}
like image 92
savepopulation Avatar answered Oct 27 '22 10:10

savepopulation