错误状态 class,需要查看状态但收到 class android.widget.CompoundButton$SavedState

Wrong state class, expecting View State but received class android.widget.CompoundButton$SavedState instead

java.lang.IllegalArgumentException: Wrong state class,需要查看状态,但收到的却是 class android.widget.CompoundButton$SavedState。当不同类型的两个视图在同一层次结构中具有相同的 id 时,通常会发生这种情况。此视图的 id 是 id/0x2。确保其他视图不使用相同的 ID。

它发生在屏幕旋转时,当尝试返回片段时没有重复 id 请有人帮助我

我已经解决了....这是因为视图的 ID 重复,主要是当我们动态添加视图而不设置 ID 时(在我的情况下具有相同的单选按钮文本)

要解决,首先检查您动态添加的所有视图

假设您在 Fragment 或 DialogFragment 中有一个 ScrollView,id 为:

android:id="@+id/scrollView"

您显示此片段,然后更改屏幕方向,并发生此崩溃:

E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo { com.company.MyApp/com.company.MyActivity }: 
    java.lang.IllegalArgumentException: Wrong state class, expecting View State 
    but received class android.widget.ScrollView$SavedState instead. 
    This usually happens when two views of different type have the same id 
    in the same hierarchy. This view's id is id/scrollView. Make sure other 
    views do not use the same id.
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
  ...
Caused by: java.lang.IllegalArgumentException: Wrong state class...
  at android.view.View.onRestoreInstanceState(View.java:13764)
  at android.support.v4.widget.NestedScrollView.onRestoreInstanceState(NestedScrollView.java:1879)
  ...

解决方法是重命名您正在使用的 ID,如下所示:

android:id="@+id/scroll_view"

我假设某些 id 名称已被 Android 框架中的其他视图使用,因此在恢复视图状态时 将它们检测为重复名称。所以你必须改变你的id的名字。

正如问题所描述的那样。

This usually happens when two views of different type have the same id in the same hierarchy.

确切地说,会有两种不同类型的视图具有相同的 id,这可能发生在动态膨胀视图上。 在我的例子中,我有两个 ViewStub 具有相同的视图 idinflatedId,因此,在一个视图的 inflation 之后。应用程序进入一种状态,即一个 ViewStub 和其他膨胀的视图存在于视图层次结构中,具有相同的 id,这导致了崩溃。

在我的例子中,我实施的 onRestoreInstanceState 没有正确地尝试将我的自定义 SavedState class 发送到 super.onRestoreInstanceState

我解决了发送 savedState.getSuperState 到 super 调用的问题。

类似的事情发生在我身上,在我的例子中,我有一种布局用于纵向模式,另一种用于横向模式。两者有相似之处,但有两个按钮在两种布局上具有相同的 Id,但是这两个按钮的类型在横向布局中不同。因此,当我将设备的方向更改为横向时,会发生类似的错误。修复是在两种布局中使用相同类型的按钮。

除了我没有重复的 ID 之外,我还收到了错误消息。 我的代码是这样的:

override fun onSaveInstanceState(): Parcelable {
    val bundle = Bundle()
    bundle.putString(SELECTED_KEY, selectedItemId)
    bundle.putParcelable(SUPER_STATE_KEY, super.onSaveInstanceState())
    return bundle
}

override fun onRestoreInstanceState(state: Parcelable) {
    if (state is Bundle) {
        selectedItemId = state.getString(SELECTED_KEY, null)
        selectedItemId?.let{
            views.forEach {view ->
                view.isSelected = it == view.tag
            }
        }
    }

    super.onRestoreInstanceState(state)
}

我看到有一个未解决的问题 here。当我像这样更改 super.onRestoreInstanceState 调用参数时,我设法找到了一个不会使应用程序崩溃的解决方法:

override fun onSaveInstanceState(): Parcelable {
    val bundle = Bundle()
    vgs_ring?.constraintLayoutParams()?.let {
        bundle.putParcelable(PARENT_STATE_KEY, super.onSaveInstanceState())
        bundle.putFloat(RING_POSITION_KEY, it.verticalBias)
    }
    super.onSaveInstanceState()
    return bundle
}


override fun onRestoreInstanceState(state: Parcelable) {
    var parentState : Parcelable? = null
    if (state is Bundle) {
        val curRingPosition = state.getFloat(RING_POSITION_KEY, DEFAULT_RING_POSITION)
        state.getParcelable<Parcelable?>(PARENT_STATE_KEY)?.let {
            parentState = it
        }
        vgs_ring?.constraintLayoutParams()?.let {
            it.verticalBias = curRingPosition
            calculateRingPosition()
        }
    }

    super.onRestoreInstanceState(parentState ?: super.onSaveInstanceState())
}

我只是在使用 customViews 和 parcelable 时处理这个问题,试图用 onSaveInstanceState()onRestoreInstanceState() 保持我的视图状态,但我遇到了同样的错误。但是,当我更改上述这些功能的实现时,我找到了解决方法。我会分享之前和之后。

这是我以前的。差别很小。

 override fun onSaveInstanceState(): Parcelable {
    val bundle = Bundle()
    bundle.putParcelable("superState", super.onSaveInstanceState())
    bundle.putParcelableArrayList("boxState", ArrayList(boxen))

    super.onSaveInstanceState()
    return bundle
}

override fun onRestoreInstanceState(state: Parcelable) {
    var viewState = state
    if (viewState is Bundle) {
        boxen = viewState.getParcelableArrayList("boxState")!!
        viewState = viewState.getParcelable("superState")!!
    }
    val test = boxen
    Log.i(TAG, "Bundle received: $boxen and $test and finally $viewState")

    super.onRestoreInstanceState(state)
}

这是我的追求。

override fun onSaveInstanceState(): Parcelable {
    val bundle = Bundle()
    bundle.putParcelable("superState", super.onSaveInstanceState())
    bundle.putParcelableArrayList("boxState", ArrayList(boxen))

    super.onSaveInstanceState()
    return bundle
}

override fun onRestoreInstanceState(state: Parcelable) {
    var viewState = state
    if (viewState is Bundle) {
        boxen = viewState.getParcelableArrayList("boxState")!!
        viewState = viewState.getParcelable("superState")!!
    }
    val test = boxen
    Log.i(TAG, "Bundle received: $boxen and $test and finally $viewState")

    super.onRestoreInstanceState(viewState)
}

我所要做的只是 return viewState 到超类而不是 state。我认为这是因为可以这么说,“观点的状态”还没有恢复。我们正在传递 state 参数,而在那一刻,根据我们收到的错误,它只是一个原始包。我们还没有提取并分配我们隐藏在第一个函数中的实际 view state(发生在 if 块中),这就是错误显示“错误状态 class”的原因,这也是为什么使用viewState 成功了。希望对您有所帮助!