在导航图范围内注入viewmodel:在onCreate()之前NavController不可用 [英] injecting viewmodel with navigation-graph scope: NavController is not available before onCreate()
问题描述
我在我的应用程序中使用了导航组件,并且还在同一图中的多个片段之间使用了共享的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
:
但是当我要执行此操作时(将ViewModel和一个图范围注入到onAttach
中),就会发生此错误:
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()
你知道我该怎么做吗?
推荐答案
简而言之,您可以懒惰地为ViewModel
提供匕首Provider
或Lazy
.
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#onCreate
尚未完成,您不能从Activity
那里获得NavController
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:
- 与
Lazy
- 与
Provided
- with
Lazy
- with
Provided
(REF: https://proandroiddev.com/dagger-2 -part-three-new-possibilities-3daff12f7ebf )
ie:将ViewModel
注入到Fragment
或导航器的实现中,如下所示:
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和Activity荒谬的生命周期非常困难.
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).
这篇关于在导航图范围内注入viewmodel:在onCreate()之前NavController不可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!