android - 使用导航图范围注入视图模型:在 onCreate() 之前 NavController 不可用
问题描述
我在我的应用程序中使用导航组件,并且还在同一个图中的多个片段之间使用共享 ViewModel。现在我想用 this 实例化带有这个图形范围的ViewModel。
如您所知,我们应该在片段中注入对象(ViewModel,..etc)onAttach
:
但是当我想这样做(在 中注入带有图形范围的 ViewModel onAttach
)时,会发生此错误:
IllegalStateException: NavController is not available before onCreate()
你知道我该怎么做吗?
解决方案
简而言之,您可以为ViewModel
懒惰提供 daggerProvider
或Lazy
.
长的解释是:
您的注射点是正确的。根据https://dagger.dev/android#when-to-inject
DaggerActivity 在调用 super.onCreate() 之前立即在 onCreate() 中调用 AndroidInjection.inject(),而 DaggerFragment 在 onAttach() 中执行相同的操作。
Activity
问题是在 Android 重新创建和Fragments
附加到的FragmentManger
时间和NavController
可以提供的时间之间的某种竞争条件。进一步来说:
Activity
已附加的一个已Fragments
被操作系统破坏(可以通过“开发人员设置”中的“不保留活动”进行复制)- 用户导航回
Activity
,操作系统继续重新创建Activity
Activity
setContentView
重新创建时调用。- 这会导致
Fragments
inFragmentManager
重新连接,这涉及调用Fragment#onAttach
- 被
Fragment
注入Fragment#onAttach
- Dagger 试图提供
NavController
但是你不能从这一点上得到NavController
,Activity
因为Activity#onCreate
还没有完成,你得到
IllegalStateException: NavController is not available before onCreate()
我找到的解决方案是懒惰地注入提供NavCotroller
或依赖于的东西NavController
(例如ViewModel
,因为Android需要NavController
nav-scoped VideModels
)。这可以通过两种方式完成:
- 和
Lazy
- 和
Provided
(参考:https ://proandroiddev.com/dagger-2-part-three-new-possibilities-3daff12f7ebf )
即:注入ViewModel
到Fragment
导航器的或实现中,如下所示:
@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
}
Dagger 在注入时不会尝试解决配置问题Fragment
,但在使用时,竞争条件将得到解决。
我真的很讨厌不能直接使用我的 viewModels 并且需要使用Provider
,但这是我看到的解决这个问题的唯一解决方法,我敢肯定这是谷歌的疏忽(我不怪他们,因为跟踪片段和活动的荒谬生命周期是如此困难)。
推荐阅读
- bash - 命令在终端中执行良好,而不是在 bash 脚本中
- r - 设置 ggplot 条形宽度但绝对大小,例如 1cm
- jekyll - Jekyll:手动将要复制到_site目录的目录和文件列入白名单
- javascript - VueJs Ajax 数据映射
- react-native - React Native Open Tab Bar in Modal(使用 expo)
- java - Maven:从一个较大项目的包中创建一个 jar
- java - 选择 JComboBox 时如何获取图像?
- swift - 无法读取 PNG 文件的 IHDR 块
- javascript - 如何使用此 javascript 处理具有不同 ID 的 8 种不同模式,而不必对每个按钮重复相同的代码?
- java - Java EE 项目中的 Log4j2 配置文件