You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android DataBinding包含布局RadioGroup选中状态异常求助

问题原因

  1. RadioButton ID重复冲突:三个复用的layout_textview_radiogroup布局中,RadioButton的ID均为rb_option1和rb_option2,导致整个布局树中多个View共享同一ID值。DataBinding通过ID比较判断选中状态时,所有同名ID的RadioButton会匹配同一个ViewModel值,返回Fragment后全部显示为最后选中的选项。
  2. 双向绑定与手动监听器冲突:同时使用@={}双向绑定和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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:07:02