android - AbstractSavedStateViewModelFactory:已注册具有给定密钥的 SavedStateProvider
问题描述
虽然它是相同的例外,但我的情况与 SavedStateProvider 不同,因为我正在使用 Nav-graph Scoped ViewModels,所以给定的键已经注册,
AbstractSavedStateViewModelFactory
与 navGraphViewModels 一起使用时发生异常。
从startFragment,到FirstPageFragment,navigateUp()
回到startFragment,然后再次访问FirstPageFragment ->crash
class FirstPageFragment: Fragment() {
private val myViewModel: MyViewModel by navGraphViewModels(R.id.nav_mission){
MyViewModel.Factory(requireActivity(), "hello world1")
}
...
我的工厂
class MyViewModel(application: Application,
savedStateHandle: SavedStateHandle,
val someString: String) : AndroidViewModel(application){
class Factory(val activity: Activity, val someString: String):
AbstractSavedStateViewModelFactory(activity as SavedStateRegistryOwner, null) {
override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MyViewModel(activity.application, handle, someString) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
...
}
这是我的 navGraph,ViewModel 用于 firstPageFragment 和 SecondPageFragment
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_main_activity"
app:startDestination="@id/startFragment">
<fragment
android:id="@+id/startFragment"
android:name="com.example.savestatehandledemo.StartFragment"
android:label="FirstPageFragment" >
<action
android:id="@+id/action_startFragment_to_nav_mission"
app:destination="@id/nav_mission" />
</fragment>
<navigation android:id="@+id/nav_mission"
app:startDestination="@id/firstPageFragment">
<fragment
android:id="@+id/firstPageFragment"
android:name="com.example.savestatehandledemo.FirstPageFragment"
android:label="FirstPageFragment" >
</fragment>
<fragment
android:id="@+id/secondPageFragment"
android:name="com.example.savestatehandledemo.SecondPageFragment"
android:label="SecondPageFragment" >
</fragment>
</navigation>
</navigation>
我创建了一个最小的示例来重现该问题。https://github.com/yatw/saveStateHandleDemo/tree/master/app/src/main/java/com/example/savestatehandledemo
此异常仅在进入导航图时发生。
请帮忙!
解决方案
所以我找到了这个异常的原因,我将活动作为 SavedStateRegistryOwner 传入AbstractSavedStateViewModelFactory
。
第二次访问 navGraph 时,我传入了相同的活动和内部类SavedStateHandleController
,SavedStateRegistry
以某种方式已经保存了状态。
(写这部分的人请解释并写进文档)
所以传入 navGraphgetBackStackEntry
更新了 viewModel 工厂
class MyViewModel(application: Application,
savedStateHandle: SavedStateHandle,
val someString: String) : AndroidViewModel(application){
class Factory(val application: Application,
val savedStateRegistryOwner: SavedStateRegistryOwner,
val someString: String):
AbstractSavedStateViewModelFactory(
savedStateRegistryOwner,
null) {
override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MyViewModel(application, handle, someString) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
在片段中使用它
class FirstPageFragment: Fragment() {
private val myViewModel: MyViewModel by navGraphViewModels(R.id.nav_mission){
MyViewModel.Factory(requireActivity().application,
findNavController().getBackStackEntry(R.id.nav_mission),
"hello world1")
}
特别感谢 EpicPandaForce,https: //stackoverflow.com/a/61649394/5777189
推荐阅读
- android - 了解给定设备是否在 AR 支持的设备列表中
- css - 将网格项目设置为共享列而不重叠
- git - 如何将分支名称作为选择参数并在第二个参数中动态填充分支,以便用户可以在詹金斯作业中选择一个分支
- pyspark - 在 pyspark 中从内存中删除数据帧时,以及如何显式删除数据帧
- java - jmeter在一个请求中避免代理
- laravel - 未定义的偏移量甚至将 foreach 循环提交到数据库
- ruby-2.0 - Rails 中的元编程
- c++ - 自制toupper:看起来相同但不相同
- c# - 如何在不指定列的情况下使用 c#.Net 将整个表从 ODBC 源复制到 SQL Server
- java - 在同一个 Java Servlet 中处理多个请求(不同或相同类型),如何处理?