Android Studio中RecyclerView的RadioButton返回页面时状态重置方法
问题现象
- RecyclerView内的RadioButton单次页面内交互逻辑正常
- 选中选项后返回上一级Fragment,再次进入当前页面时,RadioButton会默认保持上次最后一项的选中状态,未实现状态重置
- 首次进入预期效果:

- 重进页面异常效果:

原有实现代码
Fragment代码
private fun initializeRecyclerView(){ val transactionTypeLayoutManager = GridLayoutManager(context, 2) val list = TransactionType.values().toList() val transactionTypeAdapter = ManualMixTransactionTypeAdapter(list) binding?.recyclerViewTransactionType?.layoutManager = transactionTypeLayoutManager binding?.recyclerViewTransactionType?.adapter = transactionTypeAdapter transactionTypeAdapter.onTransactionTypeClicked = { viewModel.setTransactionType(it.name) Toast.makeText(context, "${it.name}", Toast.LENGTH_SHORT).show() } }
Adapter代码
var onTransactionTypeClicked: ((TransactionType) -> Unit)? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionTypeViewHolder { val layoutInflater: LayoutInflater = LayoutInflater.from(parent.context) val binding: ViewholderTransactionTypeBinding = ViewholderTransactionTypeBinding.inflate(layoutInflater, parent, false) return TransactionTypeViewHolder(binding) } override fun onBindViewHolder(holder: TransactionTypeViewHolder, position: Int) { holder.binding.rbTransactionType.setText(transactionType[position].key) holder.render( data = transactionType[position], dataIndex = position, adapterListener = { val oldTransactionType = transactionType.find { transactionType -> transactionType.isItemSelected } oldTransactionType?.apply { isItemSelected = false } val oldPosition = transactionType.indexOf(oldTransactionType) notifyItemChanged(oldPosition) }, updateListener = { newPosition -> notifyItemChanged(newPosition)}, clickListener = onTransactionTypeClicked ) }
ViewHolder代码
fun render( data: TransactionType, dataIndex: Int, adapterListener: (() -> Unit), updateListener: ((Int) -> Unit), clickListener: ((TransactionType) -> Unit)? ) { val onClickListener: View.OnClickListener = View.OnClickListener { adapterListener.invoke() data.isItemSelected = true updateListener.invoke(dataIndex) clickListener?.invoke(data) } binding.vhTransactionType.setOnClickListener(onClickListener) binding.rbTransactionType.setOnClickListener(onClickListener) binding.rbTransactionType.isChecked = data.isItemSelected }
问题根因
选中状态isItemSelected直接定义在TransactionType枚举类中,枚举本质是全局单例实例,即使退出Fragment、新建Adapter,枚举实例上之前修改的isItemSelected值会一直保留,下次进入页面读取枚举值时就会拿到上次残留的选中状态。
修复方案
方案1(最小改动)
初始化列表时主动重置所有枚举项的选中状态,清除残留值,修改Fragment中initializeRecyclerView方法即可:
private fun initializeRecyclerView(){ val transactionTypeLayoutManager = GridLayoutManager(context, 2) val list = TransactionType.values().toList() // 初始化时重置所有选项状态 list.forEach { it.isItemSelected = false } val transactionTypeAdapter = ManualMixTransactionTypeAdapter(list) binding?.recyclerViewTransactionType?.layoutManager = transactionTypeLayoutManager binding?.recyclerViewTransactionType?.adapter = transactionTypeAdapter transactionTypeAdapter.onTransactionTypeClicked = { viewModel.setTransactionType(it.name) Toast.makeText(context, "${it.name}", Toast.LENGTH_SHORT).show() } }
方案2(更优实践,避免全局状态污染)
不要把选中状态存在全局单例的枚举类中,改为Adapter内部维护选中位置,状态随Adapter生命周期绑定,Adapter销毁时状态自动清空,不会出现跨页面状态污染问题:
class ManualMixTransactionTypeAdapter( private val transactionType: List<TransactionType> ) : RecyclerView.Adapter<TransactionTypeViewHolder>() { var onTransactionTypeClicked: ((TransactionType) -> Unit)? = null // 选中位置默认-1,代表无选中项,状态仅存在于Adapter实例中 private var selectedPosition = -1 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionTypeViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val binding = ViewholderTransactionTypeBinding.inflate(layoutInflater, parent, false) return TransactionTypeViewHolder(binding) } override fun onBindViewHolder(holder: TransactionTypeViewHolder, position: Int) { val currentItem = transactionType[position] holder.binding.rbTransactionType.setText(currentItem.key) // 根据当前选中位置设置RadioButton状态 holder.binding.rbTransactionType.isChecked = position == selectedPosition val clickListener = View.OnClickListener { val currentPos = holder.bindingAdapterPosition if (currentPos == selectedPosition) return@OnClickListener // 刷新旧选中项 val oldPos = selectedPosition selectedPosition = currentPos if (oldPos != -1) notifyItemChanged(oldPos) notifyItemChanged(selectedPosition) onTransactionTypeClicked?.invoke(currentItem) } holder.binding.vhTransactionType.setOnClickListener(clickListener) holder.binding.rbTransactionType.setOnClickListener(clickListener) } override fun getItemCount(): Int = transactionType.size }
对应ViewHolder可以简化,不需要再传递多层回调处理选中逻辑。
内容的提问来源于stack exchange,提问作者Raihan Adyatma
相关产品推荐
相关产品推荐

