如何借助ViewModel在设备旋转时保存并恢复Spinner选中状态?
解决Spinner重建时选中状态被覆盖的问题
问题根源很明确:Fragment重建后,要么是设置Adapter时Spinner自动选中第0项并触发监听器,要么是你先绑定了监听器再恢复选中状态,导致代码触发的选中事件也被监听器捕获,直接覆盖了ViewModel里存的历史选中索引。
下面给你两个简单可行的解决办法:
办法一:用标志位区分手动选择和代码触发
在Fragment里加个布尔标志,只有用户手动点选Spinner的时候,才更新ViewModel的状态:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) var isRestoringState = false // 设置Spinner选中监听器 binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { // 只有非状态恢复阶段,才更新ViewModel if (!isRestoringState) { viewModel.setSelectedItem(p2) } // 用完就把标志位重置 isRestoringState = false } override fun onNothingSelected(p0: AdapterView<*>?) { // 按需实现即可 } } // 先观察数据,设置完Adapter再恢复选中状态 viewModel.spinnerData.observe(this) { spinnerArray -> ArrayAdapter( requireContext(), R.layout.simple_spinner_dropdown_item, spinnerArray ).also { adapter -> binding.spinner.adapter = adapter // 标记当前是恢复状态,避免监听器误触发更新 isRestoringState = true binding.spinner.setSelection(viewModel.getSelectedCompanyIndex()) } } }
办法二:调整顺序,先设置Adapter和恢复状态,再绑监听器
等Spinner有了数据、并且已经恢复到历史选中项之后,再绑定监听器,这样代码触发的选中事件就不会被监听器捕获:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 先监听Spinner数据变化 viewModel.spinnerData.observe(this) { spinnerArray -> ArrayAdapter( requireContext(), R.layout.simple_spinner_dropdown_item, spinnerArray ).also { adapter -> binding.spinner.adapter = adapter // 先把Spinner恢复到之前选中的位置 binding.spinner.setSelection(viewModel.getSelectedCompanyIndex()) // 最后再绑定监听器,只处理用户手动操作 binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { viewModel.setSelectedItem(p2) } override fun onNothingSelected(p0: AdapterView<*>?) { // 按需实现即可 } } } } }
两个关键提醒
- 一定要先设置Adapter,再调用setSelection,不然Spinner没有数据项,恢复选中状态的操作会无效。
- 核心思路就是把代码触发的选中事件和用户手动操作的事件区分开,避免意外覆盖ViewModel的状态。
内容的提问来源于stack exchange,提问作者yambo
相关产品推荐
相关产品推荐

