使用导航图范围注入视图模型:在 onCreate() 之前 NavController 不可用 [英] injecting viewmodel with navigation-graph scope: NavController is not available before onCreate()

本文介绍了使用导航图范围注入视图模型:在 onCreate() 之前 NavController 不可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using a navigation-component in my application and also using shared ViewModel between multiple fragments that are in the same graph. Now I want to instantiate the ViewModel with this graph scope with this.

如您所知,在片段 我们应该在 onAttach:

As you know, in fragments we should inject objects ( ViewModel,..etc ) in onAttach:

但是当我想这样做时(在 onAttach 中注入具有图形范围的 ViewModel),就会出现这个错误:

but when I want to do this (injecting ViewModel with a graph scope in onAttach), this error occurs:

IllegalStateException: NavController is not available before onCreate()

你知道我该怎么做吗?

推荐答案

简而言之,您可以使用 dagger ProviderLazy 懒惰地提供 ViewModel代码>.

In short, you could provide the ViewModel lazily with dagger Provider or Lazy.

长的解释是:

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

Your injections points are correct. According to https://dagger.dev/android#when-to-inject

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

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

问题是 Android 重新创建 Activity 和附加到 FragmentMangerFragments 之间的某种竞争条件>NavController 可以提供.更具体地说:

The problem is some kind of race condition between when Android recreates the Activity and the Fragments attached to the FragmentManger and when the NavController can be provided. More specifically:

  1. 一个带有 FragmentsActivity 被操作系统销毁(可以通过开发者设置"中的不保留活动"复制)
  2. 用户导航回Activity,操作系统继续重新创建Activity
  3. Activity 在重新创建时调用 setContentView.
  4. 这会导致 FragmentManager 中的 Fragments 被重新附加,这涉及调用 Fragment#onAttach
  5. Fragment 被注入到Fragment#onAttach
  6. Dagger 尝试提供 NavController
  1. one Activity that has Fragments attached is destroyed by the OS (can be reproduced with "don't keep Activities" from "developer settings")
  2. user navigates back to the Activity, OS proceeds to recreate the Activity
  3. Activity calls setContentView while being recreated.
  4. This causes the Fragments in the FragmentManager to be reattached, which involve calling Fragment#onAttach
  5. The Fragment is injected in Fragment#onAttach
  6. Dagger tries to provide the NavController

但此时您无法从 Activity 中获取 NavController,因为 Activity#onCreate 尚未完成而您得到>

BUT you cannot get the NavController from the Activity by this point, as Activity#onCreate has not finished yet and you get

IllegalStateException: NavController is not available before onCreate()

我发现的解决方案是注入提供 NavCotroller 或依赖于 NavController 的东西(例如 ViewModel,因为 Android 需要NavController 懒惰地获取导航范围的 VideModels).这可以通过两种方式完成:

The solution I found is to inject provide the NavCotroller or things that depend on the NavController (such as the ViewModel, because Android needs the NavController to get nav-scoped VideModels) lazily. This can be done in two ways:

  • 懒惰
  • with 提供

(参考:https://proandroiddev.com/dagger-2-第三部分新可能性-3daff12f7ebf)

即:将 ViewModel 注入 Fragment 或 navigator 的实现,如下所示:

ie: inject the ViewModel to the Fragment or implementation of navigator like this:

    @Inject
    lateinit var viewModel: Provider<ViewModel>

然后像这样使用它:

viewModel.get().events.observe(this) {....}

现在,ViewModel 可以由 Dagger 提供,例如:

Now, the ViewModel can by provided by Dagger like:


    @Provides
    fun provideViewModel(
        fragment: Fragment,
        argumentId: Int
    ): CreateMyViewModel {

        val viewModel: CreateMyViewModel
                by fragment.navGraphViewModels(R.id.nested_graph_id)

        return viewModel
    }

Fragment 被注入时,Dagger 不会尝试解析配置,但是当它被使用时,竞争条件将被解决.

Dagger won't try to resolve the provisioning when the Fragment is injected, but when it's used, hence, the race condition will be solved.

我真的很讨厌不能直接使用我的 viewModels 并且需要使用 Provider,但这是我看到的解决此问题的唯一解决方法,我确定这是 Google 的疏忽(我不怪他们,因为跟踪 Fragment 和活动的荒谬生命周期是如此困难).

I really hate not being able to use my viewModels directly and need to use Provider, but it's the only workaround I see to solve this issue, which I'm sure it was an oversight by Google (I don't blame them, as keeping track of the absurd lifecycle of Fragment and Activities is so difficult).

这篇关于使用导航图范围注入视图模型:在 onCreate() 之前 NavController 不可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆