android - 使用导航图范围 : NavController is not available before onCreate() 注入(inject) View 模型

标签 android dagger-2 android-viewmodel android-architecture-navigation fragment-lifecycle

我在我的应用程序中使用导航组件,并且还在同一个图中的多个 fragment 之间使用共享 ViewModel。现在我想用 this 用这个图范围实例化 ViewModel .

如您所知,在 fragment 中 we should inject objects ( ViewModel,..etc ) in onAttach :

但是当我想这样做(在 onAttach 中注入(inject)带有图形范围的 ViewModel)时,会发生此错误:

IllegalStateException: NavController is not available before onCreate()

你知道我该怎么做吗?

最佳答案

简而言之,您可以提供 ViewModel懒洋洋地用 Dagger ProviderLazy .

长的解释是:

您的注入(inject)点是正确的。根据 https://dagger.dev/android#when-to-inject

DaggerActivity calls AndroidInjection.inject() immediately in onCreate(), before calling super.onCreate(), and DaggerFragment does the same in onAttach().



问题是 Android 重新创建 Activity 之间的某种竞争条件。和 Fragments附于FragmentMangerNavController可以提供。进一步来说:
  • 一个 ActivityFragments附件被操作系统破坏(可以通过“开发者设置”中的“不保留 Activity ”进行复制)
  • 用户导航回 Activity , 操作系统继续重新创建 Activity
  • Activity来电setContentView在被重新创建时。
  • 这会导致 FragmentsFragmentManager要重新连接,这涉及调用 Fragment#onAttach
  • Fragment注入(inject) Fragment#onAttach
  • Dagger 尝试提供 NavController

  • 但是您无法获得 NavController来自 Activity至此,如 Activity#onCreate还没有完成,你得到
    IllegalStateException: NavController is not available before onCreate()
    

    我找到的解决方案是注入(inject)提供 NavCotroller或依赖于 NavController 的东西(例如 ViewModel ,因为 Android 需要 NavController 才能获得导航范围的 VideModels )。这可以通过两种方式完成:
  • Lazy
  • Provided

  • (编号:https://proandroiddev.com/dagger-2-part-three-new-possibilities-3daff12f7ebf)

    即:注入(inject)ViewModelFragment或像这样实现导航器:
        @Inject
        lateinit var viewModel: Provider<ViewModel>
    

    然后像这样使用它:
    viewModel.get().events.observe(this) {....}
    

    现在,ViewModel可以由 Dagger 提供,例如:
    
        @Provides
        fun provideViewModel(
            fragment: Fragment,
            argumentId: Int
        ): CreateMyViewModel {
    
            val viewModel: CreateMyViewModel
                    by fragment.navGraphViewModels(R.id.nested_graph_id)
    
            return viewModel
        }
    

    Fragment 出现时,Dagger 不会尝试解析配置。被注入(inject),但是当它被使用时,竞争条件将被解决。

    我真的很讨厌不能直接使用我的 View 模型,需要使用 Provider ,但这是我看到的解决此问题的唯一解决方法,我确信这是 Google 的疏忽(我不怪他们,因为跟踪 fragment 和 Activity 的荒谬生命周期非常困难)。

    关于android - 使用导航图范围 : NavController is not available before onCreate() 注入(inject) View 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59388229/

    相关文章:

    android - android getIntrinsicHeight 和 getIntrinsicWidth 是什么意思?

    android - Dagger 无法注入(inject)类型参数字段

    android - 如何用 Dagger2 @Inject AndroidViewModel?

    java - Android dagger2 使用 Factory 将 Intent 注入(inject) viewModel

    java - ViewModel 没有零参数构造函数错误,原因是 ViewModelFactory 一直为 null(不是 100% 确定)

    android - 用 Phonegap 中的 Next 替换软键盘上的 Go 按钮

    Android Sync Adapter 从应用程序和同步选项屏幕中删除添加帐户功能

    java - 日历 .YEAR、.MONTH、DAY_OF_MONTH 与 date.getDay() 等不同?

    android - Dagger 2 错误 : android. content.Context cannot be provided without an @Provides-annotated method

    java - 多个实例中的 Dagger 2 单例