使用导航图范围注入视图模型:在 onCreate() 之前 NavController 不可用 [英] injecting viewmodel with navigation-graph scope: NavController is not available before onCreate()
问题描述
我在我的应用程序中使用了导航组件,并且还在同一图中的多个片段之间使用了共享 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 Provider
或 Lazy
懒惰地提供 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
和附加到 FragmentManger
的 Fragments
和 之间的某种竞争条件>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:
- 一个带有
Fragments
的Activity
被操作系统销毁(可以通过开发者设置"中的不保留活动"复制) - 用户导航回
Activity
,操作系统继续重新创建Activity
Activity
在重新创建时调用setContentView
.- 这会导致
FragmentManager
中的Fragments
被重新附加,这涉及调用Fragment#onAttach
Fragment
被注入到Fragment#onAttach
- Dagger 尝试提供
NavController
- one
Activity
that hasFragments
attached is destroyed by the OS (can be reproduced with "don't keep Activities" from "developer settings") - user navigates back to the
Activity
, OS proceeds to recreate theActivity
Activity
callssetContentView
while being recreated.- This causes the
Fragments
in theFragmentManager
to be reattached, which involve callingFragment#onAttach
- The
Fragment
is injected inFragment#onAttach
- 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屋!