【问题标题】:Dagger provide a dependency that depends on the view of the activityDagger 提供了依赖于活动视图的依赖项
【发布时间】:2020-02-05 00:48:44
【问题描述】:

我有一个带有导航抽屉的活动,其中有很多片段。我使用架构组件中的导航库。在每个片段中我都必须写navController = Navigation.findNavController(activity!!, R.id.fragment_container)。我想摆脱这个样板代码。所以我决定用 Dagger 注入它。

@Module
class MainActivityModule {
    @ActivityScope
    @Provides
    fun provideNavController(activity: MainActivity): NavController {
        return Navigation.findNavController(activity, R.id.fragment_container)
    }
}

@Suppress("unused")
@Module
abstract class ActivityBuildersModule {
    @ActivityScope
    @ContributesAndroidInjector(
            modules = [MainActivityModule::class, MainActivityFragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity
}

注入片段工作正常,但当我尝试注入活动应用程序崩溃:

09-19 19:22:37.152 22342-22342/com.dmitrysimakov.gymlab
    E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dmitrysimakov.gymlab, PID: 22342
java.lang.RuntimeException: Unable to start activity
    ComponentInfo{com.dmitrysimakov.gymlab/com.dmitrysimakov.gymlab.MainActivity}:
    java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
    .....

所以我必须在活动中复制navController = Navigation.findNavController(activity!!, R.id.fragment_container)。有没有更优雅的方法来做到这一点?

【问题讨论】:

  • 你能分享一下你为此做了什么吗?目前,我已经在我的 BaseFragment 中初始化了 navController 并在所有片段中使用它。但我想在 ViewModels 中使用它也使用注入。在 ViewModels 中使用导航可以吗?我怎样才能做到这一点?
  • @akshaybhange 不要让 ViewModel 知道 Android 框架类。阅读this article了解更多详情。
  • 谢谢 Dmitry,你能分享我如何将 TextWatcher 设置为我的 EditText 吗?它是 android 框架的一部分,我使用的是 ViewModel 本身的 Textwatcher,但我找不到任何好的教程。
  • @akshaybhange 在片段中设置 TextWatcher 并在 TextWatcher 的方法中处理 viewModel 的数据。
  • @akshaybhange 我有 something 类似,但使用 OnQueryTextListener searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { //... override fun onQueryTextChange(newText: String?): Boolean{ viewModel.setSearchText(newText) return true } })

标签: android dagger-2 android-architecture-components


【解决方案1】:

应用程序因活动而崩溃,因为在调用 provideNavController 时,您尚未使用 setContentView 设置内容视图

第 1 步:如果您扩展 DaggerAppCompatActivity 复制其代码并扩展 AppCompatActivity,否则只需执行第 2 步。

第2步:将AndroidInjection.inject(this)行从onCreate方法移到setContentView(...)之后

但请注意,根据我的经验,这可能会导致其他问题,例如 this,因此为了让您从活动中获取导航控制器,最好的选择可能只是使用扩展程序,如果您有 @,实际上有一个内置的build.gradle 中的 987654328@ 依赖项:

findNavController(R.id.fragment_container)

因此,对于您的活动,您可以使用此扩展程序,无论如何,如果您使用推荐的单一活动方式,在大多数情况下,您将从片段中获得导航,并且您仍然可以使用匕首注入

【讨论】:

  • 谢谢@SamuelEminet。我不知道这些扩展。对于片段也是如此。所以我不再需要为此使用 Dagger。
【解决方案2】:

对我来说最好的解决方案是在onAttach 中注入片段并提供NavController lazily。

我认为接受的解决方案不是很好,因为将注射延迟到 setContentView 很危险:在来回导航该 Fragment 时,将再次调用 setContentView 以重新创建视图层次结构。 如果 Fragment 需要观察 ViewModels 或存储库,则需要注入它。因此,我们需要延迟观察 ViewModel 直到 setContentView,这可能会导致 Fragment 观察 ViewModel 并有多个订阅,这可能会导致错误。

确实,建议将Fragments注入onAttach:https://dagger.dev/android#when-to-inject

DaggerActivity 立即调用 AndroidInjection.inject() onCreate(),在调用 super.onCreate() 之前,而 DaggerFragment 执行 在 onAttach() 中也是如此。

我在https://stackoverflow.com/a/60061872/789110回答了这个问题

【讨论】:

    猜你喜欢
    • 2018-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    相关资源
    最近更新 更多