SavedStateProvider с данным ключом уже зарегистрирован - PullRequest
1 голос
/ 09 ноября 2019

В настоящее время я пробую новый Jetpack ViewModel с saveState.

    implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc01'

Я использую 1 Activity и пытаюсь поделиться 1 ViewModel с 2 фрагментами, но когда я пытаюсь запустить второй фрагмент, я получаюошибка из заголовка.

Вот как я вызываю ViewModel с saveInstance:

    val repository = (activity?.application as App).getRepository()
    viewModel = activity?.run {
        ViewModelFactory(repository, this, savedInstanceState).create(MainViewModel::class.java)
    } ?: throw Exception("Invalid Activity")

И это мой журнал:

java.lang.IllegalArgumentException: SavedStateProvider with the given key is already registered
    at androidx.savedstate.SavedStateRegistry.registerSavedStateProvider(SavedStateRegistry.java:111)
    at androidx.lifecycle.SavedStateHandleController.attachToLifecycle(SavedStateHandleController.java:50)
    at androidx.lifecycle.SavedStateHandleController.create(SavedStateHandleController.java:70)
    at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:67)
    at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:84)
    at com.xxx.yyy.presentation.details.DetailsFragment.onCreate(DetailsFragment.kt:29)
    at androidx.fragment.app.Fragment.performCreate(Fragment.java:2586)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:838)
    at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1197)
    at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1080)
    at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:119)
    at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1866)
    at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
    at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
    at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)

Looksкак он пытается использовать SavedState, который уже был зарегистрирован, и, следовательно, ошибка? Я думал, что в этом весь смысл библиотеки. Кто-нибудь может помочь или указать, как использовать эту передачу аргументов в ViewModel и с помощью saveStateHandle?

1 Ответ

1 голос
/ 09 ноября 2019

Вы никогда не должны звонить create самостоятельно - тем самым вы фактически не используете сохраненный ViewModel, который уже создан, в результате чего AbstractSavedStateViewModelFactory пытается зарегистрировать один и тот же ключ более одного раза.

Вместо этого вы должны передать ViewModelFactory экземпляру ViewModelProvider для извлечения уже существующей ViewModel или создать его только при необходимости:

val repository = (activity?.application as App).getRepository()
viewModel = activity?.run {
    val factory = ViewModelFactory(repository, this, savedInstanceState)
    ViewModelProvider(this, factory).get(MainViewModel::class.java)
} ?: throw Exception("Invalid Activity")

Если вы зависите от fragment-ktxверсии 1.1.0 или выше, вместо этого вы можете использовать делегат свойства by activityViewModels Kotlin, который лениво использует ViewModelProvider под капотом:

val viewModel: MainViewModel by activityViewModels {
    val repository = (activity?.application as App).getRepository()
    ViewModelFactory(repository, requireActivity(), savedInstanceState)
}
...