【问题标题】:@Provides and @Binds methods in same class Kotlin同一类 Kotlin 中的 @Provides 和 @Binds 方法
【发布时间】:2023-03-25 19:02:01
【问题描述】:

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

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

  1. 最简单的方法是将您的 @Provides 实例方法标记为静态。

  2. 如果需要将它们保留为实例方法,那么您可以 将您的模块一分为二并提取所有 @Binds 方法 到一个抽象模块中。

第二个选项在 Java 和 Kotlin 中运行良好,但第一个选项在 Java 中运行良好,但我不知道如何在 Kotlin 中实现相同的选项。如果我将 @Provides 方法移动到 Companion 对象,它会抛出 Error:(30, 1) error: @Provides methods can only be present within a @Module or @ProducerModule。 在 Kotlin 中如何做到这一点。

第二个选项:(工作)

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

第一个选项:(不工作)

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

为第一个选项生成的 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,您在评论中提供的link 让一切变得清晰,我遇到了两种实现第一个选项的方法。

更新代码:

第一个选项:(工作)

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

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

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

两者都工作得很好,但出于某种原因,第一个选项看起来对我没有吸引力,所以我更喜欢第二个选项。

【问题讨论】:

  • 你试过this吗?将@Module 添加到您的companion object,但仍会生成 2 个类。
  • 注意:dagger2 的行为已针对companion object@Module 类中进行了修改,请查看我的这个答案,stackoverflow.com/a/60064965/4936904
  • 所以这个问题不需要回答!

标签: kotlin dagger-2


【解决方案1】:

这是一个示例代码,用于演示如何在单个 Kotlin class 中使用 BindsProvides 注释方法:

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

【讨论】:

  • 除了回答问题,这样做有没有优势?这样做似乎增加了额外的代码,这与@Binds 的好处相反。这也很不寻常。
  • 我不确定我是否正确理解了您的问题,这种用法的主要区别和需要在于提供和绑定注释之间的区别。
  • 哦,对不起,我的意思是如果我们只对所有类型使用@Provides 似乎会更简单,删除伴随对象。当然,现在需要@Binds 的函数,例如fun provideMessagesViewHolderBinder(binder: MessagesViewHolder.MessagesViewHolderBinder) = ViewHolderBinder(),但是这样我们每个类型只有一行代码(不包括注释)。
  • 实际上,这取决于您的项目。在我使用上面示例的项目中,我有一个地图,其中包含具有给定键的视图持有者活页夹和视图模型工厂。我只对所有回收视图使用一个适配器,它使用密钥从地图中获取工厂和活页夹。所以我需要那个解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
相关资源
最近更新 更多