我在我的应用程序中使用导航组件,并且还在同一图中的多个片段之间使用共享的ViewModel。现在,我想使用this将此图范围实例化ViewModel。
如您所知,在片段we should inject objects ( ViewModel,..etc ) in onAttach
中:
但是当我要执行此操作(在onAttach
中向ViewModel注入图形作用域)时,会发生此错误:
IllegalStateException: NavController is not available before onCreate()
你该怎么办?
答案 0 :(得分:7)
简而言之,您可以为ViewModel
加上匕首Provider
或Lazy
。
详细的解释是:
您的注射点正确。根据{{1}}
DaggerActivity立即在以下位置调用AndroidInjection.inject() onCreate(),在调用super.onCreate()之前,DaggerFragment会执行 在onAttach()中也是如此。
问题是在Android重新创建https://dagger.dev/android#when-to-inject
和Activity
所附加的Fragments
和FragmentManger
到提供NavController
之间存在某种竞争状况。更具体地说:
Activity
的{{1}}被操作系统破坏了(可以从“开发人员设置”中复制为“不要保留活动”)Fragments
,操作系统继续重新创建Activity
Activity
在重新创建时调用Activity
。setContentView
中的Fragments
被重新连接,这涉及调用FragmentManager
Fragment#onAttach
注入Fragment
Fragment#onAttach
但是您目前无法从NavController
获得NavController
,因为Activity
尚未完成,您可以得到
Activity#onCreate
我发现的解决方案是注入IllegalStateException: NavController is not available before onCreate()
或依赖NavCotroller
的东西(例如NavController
,因为Android需要ViewModel
才能获得导航。范围内的NavController
)。这可以通过两种方式完成:
VideModels
Lazy
(REF:https://proandroiddev.com/dagger-2-part-three-new-possibilities-3daff12f7ebf)
ie:将Provided
注入到ViewModel
或这样的导航器实现中:
Fragment
然后像这样使用它:
@Inject
lateinit var viewModel: Provider<ViewModel>
现在,viewModel.get().events.observe(this) {....}
可以由Dagger提供,例如:
ViewModel
在注入
@Provides
fun provideViewModel(
fragment: Fragment,
argumentId: Int
): CreateMyViewModel {
val viewModel: CreateMyViewModel
by fragment.navGraphViewModels(R.id.nested_graph_id)
return viewModel
}
时,Dagger不会尝试解决配置,但是在使用它时,竞争条件将得到解决。
我真的很讨厌不能直接使用viewModels并需要使用Fragment
,但这是我看到的解决此问题的唯一解决方法,我确信这是Google的疏忽(我不会不要责怪他们,因为跟踪Fragment和Activity荒谬的生命周期非常困难。
答案 1 :(得分:0)
...我们应该在onAttach中注入对象(ViewModel,.. etc)...
使用by navGraphViewModels(R.id.nav_graph)
包提供的原始androidx.navigation
委托属性,目前看来是不可行的,因为是从源代码开始的
findNavController().getBackStackEntry(navGraphId)
和
public final NavController getNavController()
说:
* Returns the {@link NavController navigation controller} for this navigation host. * This method will return null until this host fragment's {@link #onCreate(Bundle)}
这是一些解决方法: