带key的PreferenceScreen旋转时崩溃问题求助
这个坑我之前也踩过!当你给PreferenceScreen设置android:key后,屏幕旋转触发配置变更时,系统会尝试像普通Preference一样保存和恢复它的状态,但PreferenceScreen的内部状态处理逻辑没做适配,直接就抛出了Wrong state class -- expecting Preference State的异常。
问题根源
PreferenceScreen本质是设置页面的根容器,设计上默认不需要设置key。一旦你给它加上key,系统就会把它当成普通Preference来处理状态流转,但它的状态类并没有按照普通Preference的规范实现,恢复时自然就出现了类型不匹配的错误。
解决方案
给你三种靠谱的处理方式,按推荐程度排序:
1. 改用PreferenceCategory控制调试项(最推荐)
把调试相关的设置项放到PreferenceCategory里,给这个Category设置key,然后控制它的可见性。既满足调试状态下显示/隐藏的需求,又完美避开PreferenceScreen的状态问题。
XML代码修改:
<android.support.v7.preference.PreferenceCategory android:key="debug_category" android:title="@string/settings_debug_title"> <!-- 这里放置所有调试相关的Preference --> </android.support.v7.preference.PreferenceCategory>
Kotlin代码修改:
caller.findPreference<PreferenceCategory>("debug_category")?.isVisible = Preferences.getPref(this).getBoolean(devKey, false)
2. 自定义PreferenceScreen跳过状态保存
如果你一定要给PreferenceScreen设置key,可以自定义一个子类,重写状态保存和恢复的方法,不让系统处理它的状态:
自定义PreferenceScreen类:
class CustomDebugPreferenceScreen(context: Context, attrs: AttributeSet) : PreferenceScreen(context, attrs) { override fun onSaveInstanceState(): Parcelable? { // 直接返回null,不保存任何状态 return null } override fun onRestoreInstanceState(state: Parcelable?) { // 不需要恢复状态,调用父类时传入null即可 super.onRestoreInstanceState(null) } }
XML中使用自定义类:
<com.your.package.name.CustomDebugPreferenceScreen android:key="debug_key_screen" android:title="@string/settings_debug_title"> <!-- 调试相关Preference --> </com.your.package.name.CustomDebugPreferenceScreen>
3. 在Fragment中移除状态保存(临时救急)
这个方法比较hack,只适合临时解决问题:在你的PreferenceFragmentCompat子类中,覆盖onSaveInstanceState方法,移除掉PreferenceScreen的状态数据:
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 移除debug_key_screen对应的状态数据 outState.remove("debug_key_screen") }
这种方式不够优雅,可能影响其他状态的正常保存,不建议长期使用。
内容的提问来源于stack exchange,提问作者adsamcik

