@在同一类Kotlin中提供和@Binds方法

@在同一类Kotlin中提供和@Binds方法,kotlin,dagger-2,Kotlin,Dagger 2,在dagger 2.11之后,我们可以使用@Binds注释并将我们的模块标记为抽象,在这种情况下,它比具体的更有效 如果我的模块同时具有@Provides和@Binds方法,我有两个选项: 最简单的方法是将@Provides实例方法标记为静态 如果有必要将它们保留为实例方法,那么您可以 将模块一分为二并提取所有@Binds方法 转换为抽象模块 第二个选项在Java和Kotlin中运行良好,但第一个选项在Java中运行良好,但我不知道如何在Kotlin中实现相同的功能。如果我将@Provides方

在dagger 2.11之后,我们可以使用@Binds注释并将我们的模块标记为抽象,在这种情况下,它比具体的更有效

如果我的模块同时具有@Provides和@Binds方法,我有两个选项:

  • 最简单的方法是将@Provides实例方法标记为静态

  • 如果有必要将它们保留为实例方法,那么您可以 将模块一分为二并提取所有@Binds方法 转换为抽象模块

  • 第二个选项在Java和Kotlin中运行良好,但第一个选项在Java中运行良好,但我不知道如何在Kotlin中实现相同的功能。如果我将@Provides方法移动到伴随对象,它会抛出
    错误:(30,1)错误:@Provides方法只能出现在@Module或@ProducerModule
    中。 在科特林怎么能做到这一点

    第二个选项:(工作)

    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()
        }
    }
    
    @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()
            }
        }
    }
    
    @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()
            }
        }
    }
    
    第一个选项:(不工作)

    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()
        }
    }
    
    @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()
            }
        }
    }
    
    @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()
            }
        }
    }
    
    为第一个选项生成的Java文件:

    @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();
            }
        }
    }
    
    更新:

    多亏了@David Medenjak您在评论中提供的信息让我明白了实现第一个选项的两种方法

    更新代码:

    第一个选项:(工作)

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


    这两种方法都很好,但由于某种原因,第一种方法看起来对我没有吸引力,所以我更喜欢第二种方法

    下面是一个示例代码,演示如何在单个
    Kotlin类中使用
    绑定
    提供
    注释方法:

    @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
    }
    
    @模块
    抽象类消息表示模块{
    @模块
    伴星{
    const val MESSAGES=0x00
    @JvmStatic
    @提供
    乐趣提供者循环适配器(
    itemComparator:DisplayItemComparator,
    工厂地图:地图,
    活页夹:地图,
    AndroidPresentations:AndroidPresentations
    ):Recycle Services水适配器{
    返回回收器适配器(
    itemComperator=itemComparator,
    viewHolderFactoryMap=factoryMap,
    viewBinderFactoryMap=binderMap,
    androidPreconditions=androidPreconditions
    )
    }
    }
    @束缚
    @英托马普
    @IntKey(信息)
    内部抽象功能提供消息ViewModelFactory(工厂:MessagesViewHolder.MessageViewHolderFactory):ViewHolderFactory
    @束缚
    @英托马普
    @IntKey(信息)
    内部抽象功能提供消息ViewHolderBinder(绑定器:MessagesViewHolder.MessagesViewHolderBinder):ViewHolderBinder
    }
    
    您试过了吗?将
    @Module
    添加到您的
    同伴对象
    ,但仍将生成2个类。注意:dagger2的行为已在
    @Module
    类中针对
    同伴对象
    进行了修改,请检查我的回答,除了回答问题外,这样做是否有好处?这样做似乎增加了额外的代码,这与
    @Binds
    的好处相反。这也是不寻常的。我不确定我是否正确理解了你的问题,这种用法的主要区别和需要在于提供和绑定注释之间的区别。哦,对不起,我的意思是,如果我们只对所有类型使用@Providers,移除伴随对象,似乎会更简单。当然,现在需要使用带有
    @Binds
    的函数,例如
    fun ProvideMessageViewHolderBinder(binder:MessagesViewHolderBinder.MessagesViewHolderBinder)=ViewHolderBinder()
    ,但这样我们每种类型只有一行代码(不包括注释)。实际上,这取决于您的项目。在我使用上述示例的项目中,我有一个地图,其中包含具有给定键的视图持有者绑定器和视图模型工厂。我只为所有recyclerviews使用一个适配器,它使用密钥从映射中获取工厂和活页夹。所以我需要这个解决方案。