How to use Two way data binding with radio button in android
Asked Answered
V

3

5

I am trying to use two way data binding with the radio button. It is working fine with one way like below,

android:checked="@{registration.gender.equals(Gender.FEMALE.getValue())}".

But My problem is that, I need to set the value of selected radio button in my model.

<?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>
      <import type="com.callhealth.customer.comman.enums.Gender" />
      <import type="android.text.TextUtils" />
      <import type="java.lang.Integer" />
      <variable name="callback" type="com.callhealth.customer.usermanagement.callback.RegistrationCallback" />
      <variable name="registration" type="com.callhealth.customer.usermanagement.model.request.LoginAndRegistrationRequestModel" />
   </data>
   <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:orientation="vertical">
      <android.support.v7.widget.AppCompatTextView android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/label_gender" android:textSize="15sp" />
      <RadioGroup android:id="@+id/gender_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:orientation="horizontal">
         <android.support.v7.widget.AppCompatRadioButton android:layout_width="wrap_content" android:checked="@={registration.gender.equals(Gender.MALE.getValue())}" android:layout_height="wrap_content" android:text="@string/label_male" />
         <android.support.v7.widget.AppCompatRadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginStart="20dp" android:checked="@={registration.gender.equals(Gender.FEMALE.getValue())}" android:text="@string/label_female" />
      </RadioGroup>
   </LinearLayout>
</layout>

My Model Class

public class LoginAndRegistrationRequestModel extends BaseObservable {

    private Integer gender;

    @Bindable
    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
        notifyPropertyChanged(BR.gender);
    }   
}

When i am trying to use

android:checked="@={registration.gender.equals(Gender.FEMALE.getValue())}" 

Gradel is throwing an error

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> android.databinding.tool.util.LoggedErrorException: Found data binding errors.
  ****/ data binding error ****msg:The expression registrationGender.equals(com.callhealth.customer.comman.enums.Gender.MALE.getValue()) cannot be inverted: There is no inverse for method equals, you must add an @InverseMethod annotation to the method to indicate which method should be used when using it in two-way binding expressions
  file:S:\Umesh\android\android_studio_workspace\CallHealth\app\src\main\res\layout\content_user_registration.xml
  loc:148:48 - 148:97
  ****\ data binding error ****
Vigesimal answered 9/3, 2018 at 13:1 Comment(0)
T
6

Try it

After some hours I found an easy way: two-way databinding in android. Its a base skeleton with livedata and Kotlin. Also, you can use ObservableField()

  • Set your viewmodel to data
  • Create your radiogroup with buttons as you like. Important: set all radio buttons id !!!
  • Set in your radio group two-way binding to checked variable (use viewmodel variable)
  • Enjoy)

layout.xml

<data>
    <variable
        name="VM"
        type="...YourViewModel" />
</data>


<LinearLayout
            android:id="@+id/settings_block_env"
            ...
            >


            <RadioGroup

                android:id="@+id/env_radioGroup"
                android:checkedButton="@={VM.radio_checked}">

                <RadioButton
                    android:id="@+id/your_id1"/>

                <RadioButton
                   android:id="@+id/your_id2" />

                <RadioButton
                    android:id="@+id/your_id3"/>

                <RadioButton
                    android:id="@+id/your_id4"/>
            </RadioGroup>

        </LinearLayout>
class YourViewModel(): ViewModel {
    
    var radio_checked = MutableLiveData<Int>()
    
    
    init{
        radio_checked.postValue(R.id.your_id1)//def value
    }
    
    //other code
    }

Tesler answered 18/1, 2019 at 22:19 Comment(1)
So the radio_checked stores the id? What if I want the index (position)?Obsolescent
M
0

You are binding it to a boolean EXPRESSION. It has no idea what method to call when setting it. I would try making your property a boolean (e.g. isFemale). It sounds like there is also a way to indicate the setter with the @InverseMethod annotation, but I haven't used that and it seems to me that the boolean approach would be more straightforward. You could always implement the boolean properties in terms of the Integer gender field if you wanted to refer to the Integer elsewhere in java code.

Mathieu answered 10/3, 2018 at 17:55 Comment(0)
R
0

You can either create a @InverseMethod for the custom converter (the error says it can't convert equals to gender basically) or just use a boolean observable for the changes and the setter will work out of the box.

for example if you have

val isFemale = ObservableBoolean() 

in your ViewModel this will work out of the box

android:checked="@={viewModel.isFemale}" 

of course you need to provide ViewModel variable into the layout binding.

To "fix" what you have there you need to create your own inverse method and setter for checked.

@InverseMethod("toGender")
public static int isFemaleGender(Integer gender) {
        return gender.equals(Gender.FEMALE.getValue());
    } 

public static Integer toGender(boolean checked) {
        if (checked) 
           return Gender.FEMALE;
        else 
           return Gender.MALE;
    }

Both of these approaches will only work if you have 2 options as you do true false basically. It is either you create an Observable for each option or go with the solution provided by @Serega Maleev

Rosarosabel answered 16/3, 2020 at 14:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.