android - 抽象保存状态 View 模型工厂 : SavedStateProvider with the given key is already registered

标签 android android-fragments androidx android-viewmodel

虽然是同样的异常,但是我的情况和SavedStateProvider with the given key is already registered不一样因为我正在使用 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
此异常仅在进入导航图时发生。

请帮忙!

最佳答案

所以我找到了这个异常的原因,我将 Activity 作为 AbstractSavedStateViewModelFactory 中的 SavedStateRegistryOwner 传递。
第二次访问 navGraph 时,我传递了相同的 Activity 和内部类 SavedStateHandleControllerSavedStateRegistry 不知何故已经保存了状态。 (请写这部分的人解释并写入文档)

所以传入navGraph getBackStackEntry
更新的 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")
        }
    }

在 fragment 中使用它

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 - 抽象保存状态 View 模型工厂 : SavedStateProvider with the given key is already registered,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69777585/

相关文章:

android - 无法在android中使用比较器对数据进行排序

android - RecyclerView 与 ViewPager 中的 StaggeredGridLayoutManager,返回 fragment 时自动排列项目

android - addToBackStack 不适用于 onBackPressed 方法

kotlin - 2x NavHostFragments 在 LayoutInspector 中可见,但在我的布局中只有 1 个

androidx.navigation.fragment.NavHostFragment 无法从 xml 文件访问

android-recyclerview - 索引越界异常 : Inconsistency detected error while scrolling

android - 如何在样式上有效地用 maxLines 替换 singleLine?

android - 在单个目录中存储多个音频文件-Android

android - 从 DialogFragment 打开 fragment (替换 Dialogs 父级)

java - 从 java 返回一个 float 数组到 jni