android-fragments 已注册具有给定密钥的SavedStateProvider

xeufq47z  于 2022-11-14  发布在  Android
关注(0)|答案(2)|浏览(138)

我目前正在尝试使用带有savedState的新Jetpack ViewModel。

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

我正在使用1个Activity,并尝试与2个片段共享1个ViewModel,但当我尝试启动第二个片段时,我从标题中得到错误。
下面是我如何使用savedInstance调用ViewModel:

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)

看起来它试图使用一个已经注册的SavedState,因此出现了错误?我认为这就是这个库的全部意义。有人能帮助或指出如何使用这个传递参数给ViewModel和使用savedStateHandle吗?

fcg9iug3

fcg9iug31#

您永远不应该自己调用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")

如果您依赖1.1.0或更高版本的fragment-ktx,则可以改用by activityViewModelsKotlin属性委托,该委托在幕后惰性地使用ViewModelProvider

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

4dc9hkyq2#

当我遇到 given key is already registered 错误时,我确实检查了thisthisthis。但我没有找到任何有用的信息。在我的案例中,这个问题是与莫希Json Generators有关。

文件1:受害者视图模型.kt

class VictimViewModel constructor(
  private val searchManager: SearchManager,
) : ViewModel() {

}

文件2:搜索管理器.kt

class SearchManager internal constructor(
  private val SearchApi: SearchApi
) {
  fun searchString(token: String): Either<A, B> {
    return searchApi
      .searchString(token)
      .process(
        this::parseResponse
      )
  }
}

文件3:搜索API.kt

internal interface SearchApi {
@GET("$BASE_PATH/search_string")
  fun searchString(@Query("search_string") token: String): NetworkEither<SearchResponse>
}

文件4:SearchResponse.kt(此文件包含根本原因)

data class SearchResponse(
  @Json(name = "suggestions")
  val suggestions: List<String>
)

上面的代码有什么问题?

我忘了给SearchResponse数据类添加@JsonClass(generateAdapter = true)注解。这破坏了注入机制,并在初始化ViewModel时开始抛出key is already registered错误。错误消息和实际问题完全无关。所以,我花了一段时间才理解这个问题。

**解决方案:**更新文件4:搜索响应.kt如下所示

@JsonClass(generateAdapter = true)
data class SearchResponse(
  @Json(name = "suggestions")
  val suggestions: List<String>
)

相关问题