0

I have a list of items. In each item's row I have 2 EditTexts side-by-side. EditText-2 depends on EditText-1's value. This list is bound with data-binding values in HashMap<String, ItemValues>

For Example:

Total     _____1000____
Item A    __1__ __200__
Item B    __1__ __200__
Item C    __1__ __200__
Item D    __2__ __400__

First EditText is the share and the second value is its value calculated based on total and share. So, in example if I change any 1 share, all the values will be changed. So, shown in example total no of shares are = 1+1+1+2 = 5. So amount per share = 1000/5 = 200 and is calculated and shown in next EditText.

I have bound this values with two-way data binding like this:

As, this is a double value, I have added 2 binding adapters for this like this:

@BindingAdapter("android:text")
public static void setShareValue(EditText editText, double share) {
    if (share != 0) {
        editText.setText(String.valueOf(share));
    } else {
        editText.setText("");
    }
}

@InverseBindingAdapter(attribute = "android:text")
public static double getShareValue(EditText editText) {
    String value = editText.getText().toString();
    if (!value.isEmpty()) {
        return Double.valueOf(value);
    } else
        return 0;
}

Now, to calculate new values, I need to re-calculate whole thing after any share value is changed. So, I added android:onTextChagned method to update Calculations. But it gets me an infinite loop.

<EditText
    android:text="@={items[id].share}"
    android:onTextChanged="handler.needToUpdateCalculations"
    .... />

public void needToUpdateCalculations(CharSequence charSequence, int i, int i1, int i2) {
    updateCalculations();
}

This gets an infinete loop because when data changes, it is rebound to the EditText, and each EditText has an onTextChanged attached it will fire again and it will get really large - infinite loop.

It also updates the value of itself, ended up loosing the cursor as well.

I have also tried several other methods like adding TextWatcher when on focus and removing when losses focus. But at least it will update it self and will loose the cursor or infinite loop.

Unable to figure this problem out. Thank you for looking into this problem.

EDIT:

I have tried with the below method. But, it doesn't allow me to enter . (period).

@BindingAdapter("android:text")
public static void setDoubleValue(EditText editText, double value) {
    DecimalFormat decimalFormat = new DecimalFormat("0.##");
    String newValue = decimalFormat.format(value);
    String currentText = editText.getText().toString();

    if (!currentText.equals(newValue)) {
        editText.setText("");
        editText.append(newValue);
    }
}
kirtan403
  • 7,293
  • 6
  • 54
  • 97

1 Answers1

1

The reason you stated is correct and it will make a infinite loop definitely. And there is a way to get out from the infinite loop of this problem, android official provided a way to do so (But it is not quite obvious.)(https://developer.android.com/topic/libraries/data-binding/index.html#custom_setters)

Binding adapter methods may optionally take the old values in their handlers. A method taking old and new values should have all old values for the attributes come first, followed by the new values:

    @BindingAdapter("android:paddingLeft")
    public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
       if (oldPadding != newPadding) {
           view.setPadding(newPadding,
                           view.getPaddingTop(),
                           view.getPaddingRight(),
                           view.getPaddingBottom());
       }
    }

You can use the old value and new value comparison to make the setText function called conditionally.

@BindingAdapter("android:text")
public static void setShareValue(EditText editText, double oldShare,double newShare) {
    if(oldShare != newShare)
    {
        if (newShare!= 0) {
            editText.setText(String.valueOf(newShare));
        } else {
            editText.setText("");
        }
    }
}
Long Ranger
  • 5,888
  • 8
  • 43
  • 72
  • Hi Long, unfortunately It is still going into the infinite loop. – kirtan403 Sep 13 '16 at 11:48
  • I have seen many posts of yours in android data-binding. It looks like you are well aware of android's data-binding. Can you explain me that what is the use of InverseBindingAdapter? When it is called and for what purpose in 2-way data-binding? Because I have defined it, I am unable to understand its use. Very few(actually almost zero) posts are there explaining InverseBindingAdapter or use of AttrChanged. – kirtan403 Sep 13 '16 at 11:53
  • I have tried a different format, which actually worked well, but doesn't allow me `.` to be entered, because after parsing it gets the original double. – kirtan403 Sep 13 '16 at 11:56
  • May be my if else statement is wrong. I will correct it later. In my mind it should be possible to enter `.` character. If you are talking about the InverseBindingAdapter. See my reply here,http://stackoverflow.com/questions/37874091/android-spinner-data-binding-using-xml-and-show-the-selected-values/39444728#39444728 , I have tried to make some custom two-way binding for the spinner selection. I thought why the variable got callback is because the InverseBindingListener onChange() function is called. But the founder of the data binding should have better explanation than mine. – Long Ranger Sep 14 '16 at 07:04
  • Thanks. I have seen that answer. It really helped me understand better. But still, not able to understand fully. I am not finding any article which explains this in a simple and better way. I have really messed with this and came with really ugly solution which at least works. Will post that after some cleaning up. – kirtan403 Sep 14 '16 at 07:35
  • For mine, it is also right, Hope @George Mount can have some explanation about it. – Long Ranger Sep 14 '16 at 07:46