user3339689
user3339689

Reputation: 113

Android Databinding, Listening changes in 2 EditTexts

I already found the question here , but it didn't really work for me. I have a currency converter with two edit texts which convert from INR to USD and vise versa. I need to use DataBinding to listen to the changes of each Edittext, and update the currency value of the next EdittText

Hers my code

public class BindingViewModel extends BaseObservable {
public ObservableField<Double> inr = new ObservableField<>();
public ObservableField<Double> dollar = new ObservableField<>();

public void onINRTextChanged(CharSequence s, int start, int before, int count) {
    double aDouble = Double.parseDouble(s.toString());
    dollar.set(aDouble * 0.014);
}

public void onDOLLARTextChanged(CharSequence s, int start, int before, int count) {
    Log.d("tag", "onTextChanged " + s);
    double aDouble = Double.parseDouble(s.toString());
    inr.set(71.92 * aDouble);
 }
}

And XML

<?xml version="1.0" encoding="utf-8"?>
<layout>

<data>

    <variable
        name="vm"
        type="android.com.tasks.BindinfViewModel" />
</data>

<android.support.constraint.ConstraintLayout 
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/inr"
        android:layout_width="108dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:ems="10"
        android:inputType="number"
        android:onTextChanged="@{vm.onDOLLARTextChanged}"
        android:text="@{String.valueOf(vm.inr)}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.17"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/dollar"
        android:layout_width="108dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:ems="10"
        android:inputType="number"
        android:onTextChanged="@{vm.onINRTextChanged}"
        android:text="@{String.valueOf(vm.dollar)}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/inr"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="INR"
        app:layout_constraintEnd_toEndOf="@+id/inr"
        app:layout_constraintStart_toStartOf="@+id/inr"
        app:layout_constraintTop_toBottomOf="@+id/inr" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="DOLLAR"
        app:layout_constraintEnd_toEndOf="@+id/dollar"
        app:layout_constraintStart_toStartOf="@+id/dollar"
        app:layout_constraintTop_toBottomOf="@+id/dollar" />
</android.support.constraint.ConstraintLayout>
</layout>

Here, whenever I enter something in any of the EditTexts, both are going to an infinite loop since both text change listeners continuously triggering on each value update. I can solve this issue by manually adding a TextWatcher to each of the EditTexts and temporarily making textChangelistener as null just before setting the value to avoid infinite looping. Is there any other efficient way using databinding to do this?

Upvotes: 0

Views: 407

Answers (1)

arsalanelec
arsalanelec

Reputation: 258

I suggest you use two-way binding. you can write setter and getter for your fields like below and then use android:text="@={fieldName}" instead of android:text="@{fieldName}". your Model class will maybe like this:

public class BindingViewModel extends BaseObservable {
public Double inr = 0.0;
public Double dollar = 0.0;

@Bindable
public String getInrString() {
    String inrString = String.valueOf(inr);
    if (inrString.endsWith(".0"))
        return inrString.substring(0, inrString.length() - 2);
    return inrString;
}

public void setInrString(String inrString) {
    if (inrString != null && !inrString.isEmpty()) {
        double newInr = Double.parseDouble(inrString);
        if (this.inr != newInr) {
            this.inr = newInr;
            dollar = inr * 0.014;
        }
    } else {
        inr = 0.0;
        dollar = 0.0;
    }
    notifyPropertyChanged(BR.dollarString);
}

@Bindable
public String getDollarString() {
    String dollarString = String.valueOf(dollar);
    if (dollarString.endsWith(".0"))
        return dollarString.substring(0, dollarString.length() - 2);
    return dollarString;
}

public void setDollarString(String dollarString) {
    if (dollarString != null && !dollarString.isEmpty()) {
        double newDollar = Double.parseDouble(dollarString);
        if (this.dollar != newDollar) {
            this.dollar = newDollar;
            inr = dollar * 71.92;
        }
    } else {
        inr = 0.0;
        dollar = 0.0;
    }
    notifyPropertyChanged(BR.inrString);
}
}

and you Layout XML:

<layout>
<data>
    <variable
        name="vm"
        type="com.BindingViewModel" />
</data>

<android.support.constraint.ConstraintLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/inr"
        android:layout_width="108dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:ems="10"
        android:inputType="number"
        android:text="@={vm.inrString}"
        android:selectAllOnFocus="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.17"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/dollar"
        android:layout_width="108dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:ems="10"
        android:inputType="number"
        android:text="@={vm.dollarString}"
        android:selectAllOnFocus="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/inr"
        app:layout_constraintTop_toTopOf="parent" />
...

and ofcourse if your activity you need to set your viewModel:

BindingViewModel viewModel=new BindingViewModel();
    binding.setVm(viewModel);

Upvotes: 1

Related Questions