Android DataBinding包含布局RadioGroup选中状态异常求助
问题原因
- RadioButton ID重复冲突:三个复用的
layout_textview_radiogroup布局中,RadioButton的ID均为rb_option1和rb_option2,导致整个布局树中多个View共享同一ID值。DataBinding通过ID比较判断选中状态时,所有同名ID的RadioButton会匹配同一个ViewModel值,返回Fragment后全部显示为最后选中的选项。 - 双向绑定与手动监听器冲突:同时使用
@={}双向绑定和setOnCheckedChangeListener手动同步状态,两种机制互相干扰,导致状态同步逻辑混乱。
解决方案
步骤1:替换ID为自定义状态值
修改layout_textview_radiogroup.xml,将选中状态判断从基于View ID改为基于整数状态(0代表选项1,1代表选项2),避免ID重复问题:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="tvText" type="String" /> <variable name="option1Text" type="String" /> <variable name="option2Text" type="String" /> <!-- 用整数0/1代表选中选项,替代View ID --> <variable name="selectedOption" type="Integer" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/layout_textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{tvText}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="Some Text"/> <RadioGroup android:id="@+id/radioGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" app:layout_constraintTop_toBottomOf="@id/layout_textview"> <RadioButton android:id="@+id/rb_option1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:checked="@{selectedOption == 0}" android:text="@{option1Text}" tools:text="Option 1" /> <RadioButton android:id="@+id/rb_option2" android:layout_width="match_parent" android:layout_height="wrap_content" android:checked="@{selectedOption == 1}" android:text="@{option2Text}" tools:text="Option 2" /> </RadioGroup> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
步骤2:调整ViewModel初始状态
将ViewModel中选中状态的初始值设为-1(表示未选中),确保状态逻辑清晰:
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class RadioViewModel @Inject constructor(): ViewModel() { // 初始值设为-1表示未选中 var selectedQuestion1OptionId = MutableLiveData(-1) var selectedQuestion2OptionId = MutableLiveData(-1) var selectedQuestion3OptionId = MutableLiveData(-1) }
步骤3:移除手动监听器,依赖双向绑定
删除RadioFragment.kt中的setUpRadioClickListener方法,双向绑定会自动处理状态同步:
import android.os.Bundle import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import androidx.navigation.fragment.findNavController import com.yousuf.demo.BaseFragment import com.yousuf.demo.R import com.yousuf.demo.databinding.FragmentRadioBinding import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class RadioFragment : BaseFragment<FragmentRadioBinding>() { private val viewModel: RadioViewModel by hiltNavGraphViewModels(R.id.radio_nav_graph) override fun inflateLayout(inflater: LayoutInflater): FragmentRadioBinding { return FragmentRadioBinding.inflate(inflater) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.viewModel = viewModel binding.fragment = this@RadioFragment } fun navigateToSomeFragment() { findNavController().navigate(R.id.action_radioFragment_to_someFragment) } }
步骤4:添加RadioGroup双向绑定适配器(可选优化)
创建BindingAdapters.kt,实现RadioGroup与ViewModel状态的双向绑定:
import android.widget.RadioGroup import androidx.databinding.BindingAdapter import androidx.databinding.InverseBindingAdapter import androidx.databinding.InverseBindingListener @BindingAdapter("selectedOption") fun setSelectedOption(radioGroup: RadioGroup, value: Int?) { val selectedId = when (value) { 0 -> radioGroup.getChildAt(0).id 1 -> radioGroup.getChildAt(1).id else -> -1 } if (radioGroup.checkedRadioButtonId != selectedId) { radioGroup.check(selectedId) } } @InverseBindingAdapter(attribute = "selectedOption") fun getSelectedOption(radioGroup: RadioGroup): Int { return when (radioGroup.checkedRadioButtonId) { radioGroup.getChildAt(0).id -> 0 radioGroup.getChildAt(1).id -> 1 else -> -1 } } @BindingAdapter("selectedOptionAttrChanged") fun setListener(radioGroup: RadioGroup, listener: InverseBindingListener?) { if (listener != null) { radioGroup.setOnCheckedChangeListener { _, _ -> listener.onChange() } } }
然后在layout_textview_radiogroup.xml的RadioGroup中添加绑定:
<RadioGroup android:id="@+id/radioGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" app:selectedOption="@={selectedOption}" app:layout_constraintTop_toBottomOf="@id/layout_textview">
验证效果
完成以上修改后,选择不同选项并导航返回,每个单选框会保持之前的选中状态,不会全部变为最后选中的选项。
内容的提问来源于stack exchange,提问作者Muhammad Yousuf
相关产品推荐
相关产品推荐

