我正试图找出一种不太典型的方法来实现一个ActivityModule,用于我所有的应用程序活动.这是我当前的设置:

ActivityModule:

@Module
class ActivityModule(private val activity: Activity) {

    @Provides @ActivityScope
    fun providesActivity(): Activity = activity

    @Provides @ActivityContext @ActivityScope
    fun providesContext(): Context = activity

    @Provides @ActivityContext @ActivityScope
    fun providesLayoutInflater(): LayoutInflater = activity.layoutInflater

    @Provides @ActivityContext @ActivityScope
    fun providesResources(): Resources = activity.resources

}

AppActivityModule(为雄激素注射模块提供活动)

@Module(subcomponents = [
        AppActivityModule.WelcomeActivityComponent::class
    ])
    internal abstract class AppActivityModule {

        @Binds 
        @IntoMap 
        @ActivityKey(WelcomeActivity::class)
        abstract fun bindWelcomeActivityInjectorFactory(builder: WelcomeActivityComponent.Builder): AndroidInjector.Factory<out Activity>

        @ActivityScope
        @Subcomponent(modules = [(ActivityModule::class)])
        interface WelcomeActivityComponent : AndroidInjector<WelcomeActivity> {
        @Subcomponent.Builder abstract class Builder : AndroidInjector.Builder<WelcomeActivity>() {
            abstract fun activityModule(myActivityModule: ActivityModule): AndroidInjector.Builder<WelcomeActivity>

            override fun seedInstance(instance: WelcomeActivity) {
                activityModule(ActivityModule(instance))
            }
        }
    }
}

我想要的是AppActivityModule:

@Module
internal abstract class AppActivityModule {
    @ContributesAndroidInjector(modules = [(ActivityModule::class)])
    abstract fun contributeWelcomeActivityInjector(): WelcomeActivity
}

But this, quite understandbly, gives me an error /di/AppActivityModule_ContributeWelcomeActivityInjector.java:29: error: @Subcomponent.Builder is missing setters for required modules or subcomponents: [...di.modules.ActivityModule]

我的问题是——有没有一种更简单的方式来实现我想要做的事情?我知道@Bind@BindsInstance(从this answer开始),但这似乎只适用于我每个活动都有一个模块,并绑定具体的活动类型的情况,在本例中我不希望这样——我希望ActivityModule与所有活动一起工作.

推荐答案

最小化样板文件的一种方法是创建一个通用ActivityModule,然后 for each Activity创建一个特定的小模块.

// Abstract class so you don't have to provide an instance
@Module
abstract class ActivityModule {

    // No need for ActivityScope: You're always binding to the same Activity, so
    // there's no reason to have Dagger save your Context instance in a Provider.
    @Binds @ActivityContext
    abstract fun providesContext(activity: Activity): Context

    // This doesn't *have* to be in a companion object, but that way
    // Android can do a static dispatch instead of a virtual method dispatch.
    // If you don't need that, just skip the constructor arguments and make these
    // normal methods and you'll be good to go.
    companion object {
        @Provides @ActivityContext
        fun providesLayoutInflater(activity: Activity): LayoutInflater = 
            activity.layoutInflater

        @Provides @ActivityContext
        fun providesResources(activity: Activity): Resources = activity.resources
    }
}

(在2.26之前的Dagger版本中,您可能需要在您的同伴对象上添加@Module,在您的@JvmStatic上添加@this previous revision中提供的方法.自2020年1月的Dagger 2.26以来,这些都不是必需的.谢谢arekolek!)

以及你的模块:

@Module
internal abstract class AppActivityModule {

    @Module
    internal interface WelcomeActivityModule {
      // The component that @ContributesAndroidInjector generates will bind
      // your WelcomeActivity, but not your Activity. So just connect the two,
      // and suddenly you'll have access via injections of Activity.
      @Binds fun bindWelcomeActivity(activity: WelcomeActivity) : Activity
    }

    @ContributesAndroidInjector(
        modules = [ActivityModule::class, WelcomeActivityModule::class])
    abstract fun contributeWelcomeActivityInjector(): WelcomeActivity
}

Note that though this works for Activity, Service, BroadcastReceiver, and others, you might not want to be so quick about it for Fragment. This is because dagger.android handles fragment hierarchies with parent fragments, so from within a child component you might have access to YourApplication, YourActivity, YourParentFragment, and YourChildFragment, and all of their components. If something in YourChildFragmentComponent depends on an unqualified Fragment, it would be ambiguous whether it really wants YourParentFragment or YourChildFragment. That said, this design does make sense for Activities and certain Fragments, so it makes sense to use it (cautiously).


@ActivityContext人在这里干什么?

@ActivityContext这里是您要定义的qualifier annotation,您可以使用它来区分Dagger和其他DI框架中相同类型的绑定,可能是@ApplicationContext Context@ActivityContext Context.可以不使用它来try 它,但我强烈建议保留它,并避免绑定不合格的上下文:应用程序和活动上下文可能不同,尤其是在多屏幕或自动环境中,为了获得正确的资源和数据,您应该准确地了解您使用的内容.你可以以this one为例.

Kotlin相关问答推荐

Kotlin协程挂起继续线程

Kotlin是否针对范围和进度优化sum()?

将基于注册的服务转换为流

KMP:未能添加cafe.adriel.voyager依赖项

T和T有什么区别:任何>

Kotlin-elvis算子don';不使用map.get()

禁用 Gradle执行消息

用于将 0.5 变为 0 的 round() 函数的模拟

如果不在可组合函数中,如何获取 stringResource

为什么这个 Kotlin 代码不起作用? (如果 str[index] 在列表中,则打印)

匹配在单词边界上包含特殊字符的变量字符串的正则表达式

从 Kotlin 调用 Java 时可以为空的规则是什么

JavaFX - 你如何在 Kotlin 中使用 MapValueFactory?

嵌套数组 indexOf()

类型不匹配:Required: Context, Found: Intent

Kotlin 插件错误:无法为类 org.jetbrains.kotlin.gradle.tasks.KotlinCompile 生成代理类

Kotlin 方法重载

在用Kotlin编写的Android库公共API中处理R8+JvmStatic Annotation+Lambda

Kotlin 中的内联构造函数是什么?

Kotlin中的函数接口