Dagger2 无法提供 activity 对匕首的依赖

Dagger2 Can't provide dependency of activity to dagger

MainActivity cannot be provided without an @Inject constructor or an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.

我用的是dagger-android,我通过AndroidInjection.inject(this)注入了MainActivity,但是在Module中还是不可用。我准备了示例项目:https://github.com/deepsorrow/test_daggerIssu.git,文件如下:

FactoryVmModule:

@Module
class FactoryVmModule {

    @Provides
    @Named("TestVM")
    fun provideTestVM(
        activity: MainActivity, // <--- dagger can't inject this
        viewModelFactory: ViewModelFactory
    ): TestVM =
        ViewModelProvider(activity, viewModelFactory)[TestVM::class.java]

}

MainActivityModule:

@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun injectMainActivity(): MainActivity
}

MainActivity(使用 DaggerAppCompatActivity):

class MainActivity : DaggerAppCompatActivity() {

    @Named("TestVM")
    @Inject
    lateinit var testVM: TestVM

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

测试应用程序:

class TestApplication : Application(), HasAndroidInjector {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent.create().inject(this)
    }

    override fun androidInjector() = dispatchingAndroidInjector
}

应用程序组件:

@Component(modules = [AndroidInjectionModule::class, MainActivityModule::class, ViewModelModule::class, FactoryVmModule::class])
interface AppComponent {
    fun inject(application: TestApplication)
}

dagger.android does do this automatically: See the explicit version of the binding that @ContributesAndroidInjector generates for you, where the generated AndroidInjector.Factory contains a @BindsInstance binding 您在此处请求的类型。

这对您不起作用,因为您在 top-level 组件上安装的绑定中注入 MainActivity。这是一个问题,因为 AppComponent 将在 Activity 之前存在,并且随着 Android 重新创建 Activity 也将被替换:通过 @Component.Builder 传递实例是 不是解决这个问题的方法。

相反,将您的 FactoryVmModule::class 移动到 @ContributesAndroidInjector 生成的子组件中,您可以通过将其包含在 modules attribute on @ContributesAndroidInjector 中来实现。 Dagger 将为每个 Activity 实例创建一个不同的子组件实例,因此您的 FactoryVmModule 将始终具有与 MainActivity.

的全新绑定
@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector(
        modules = [ViewModelModule::class, FactoryVmModule::class]
    )
    abstract fun injectMainActivity(): MainActivity
}

我也把你的 ViewModelModule class 移到了那里;尽管如果它不依赖于属于 Activity 的任何内容,您可以将其留在 top-level 组件中,但您可能希望将它们放在一起。子组件中的绑定继承自应用程序,因此您可以从 Activity 的子组件中注入 AppComponent-level 绑定,但反之则不行。这意味着您将无法在 Activity 之外注入 VM 实例(此处为 TestVM),但如果它们依赖于 Activity,您无论如何都不想这样做:这些实例可能会过时并防止垃圾收集器回收您完成的 Activity 个实例。