zebleckDAMM
zebleckDAMM

Reputation: 333

How to prevent an infinite loop with two EditTexts?

I have two TextViews EditText and have assigned each on a TextChangedListener, which reference each other, changing the text of the other textview. Specifically:

rateText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if(!rateText.getText().toString().equals("")) {
                float price = Float.parseFloat(priceText.getText().toString());
                float rate = Float.parseFloat(rateText.getText().toString());

                // REFERNCES THE OTHER TEXT
                amountText.setText(Float.toString(price / rate));
            } else {
                amountText.setText("");
            }
        }
    });
    amountText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if(!rateText.getText().toString().equals("")) {
                float price = Float.parseFloat(priceText.getText().toString());
                float amount = Float.parseFloat(amountText.getText().toString());

                // REFERNCES THE OTHER TEXT
                rateText.setText(Float.toString(price / amount));
            } else {
                rateText.setText("");
            }
        }
    });

This results in an infinite loop, because each listener causes the other one to trigger. How can i prevent this without needing a button or something?

Upvotes: 0

Views: 1414

Answers (2)

Micha F.
Micha F.

Reputation: 634

You could hold the TextWatchers in fields and use a static method to set the text "silently" without notifying the listeners like this:

private TextWatcher rateWatcher; //hold watchers in fields
private TextWatcher amountWatcher;  

//...  
void yourMethodOrCallback() { //whatever
//...
    amountWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (!rateText.getText().toString().equals("")) {
                float price = Float.parseFloat(priceText.getText().toString());
                float amount = Float.parseFloat(amountText.getText().toString());

                // REFERNCES THE OTHER TEXT
                setTextSilently(amountText, amountWatcher, Float.toString(price / amount));

            } else {
                setTextSilently(rateText, rateWatcher, "");
            }
        }
    };
    rateWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (!rateText.getText().toString().equals("")) {
                float price = Float.parseFloat(priceText.getText().toString());
                float rate = Float.parseFloat(rateText.getText().toString());

                // REFERNCES THE OTHER TEXT
                setTextSilently(amountText, amountWatcher, Float.toString(price / rate));
            } else {
                setTextSilently(amountText, amountWatcher, "");
            }
        }
    };
    rateText.addTextChangedListener(rateWatcher);
    amountText.addTextChangedListener(amountWatcher);

}

private static void setTextSilently(EditText editText, TextWatcher textWatcher, CharSequence text) {
    editText.removeTextChangedListener(textWatcher); //removing watcher temporarily
    editText.setText(text); //setting text
    editText.addTextChangedListener(textWatcher); //readding watcher 
}

Upvotes: 1

da Vorci
da Vorci

Reputation: 21

I would agree with @Lotharyx's suggestion to try using a boolean first. The boolean variable should only have to be final if declared in the same scope as the method where you are adding these TextWatchers, otherwise you can use an instance variable (doesn't have to be static).

Another thing you could try is to remove the TextWatcher before the body of code in afterTextChanged(), and add it again after you have call setText() on the other EditText. But this would also require you to make the TextWatcher objects instance variables or declare them as final.

    @Override
    public void afterTextChanged(Editable s) {
        rateText.removeTextChangedListener(rateTextListener);

        if(!rateText.getText().toString().equals("")) {
            float price = Float.parseFloat(priceText.getText().toString());
            float amount = Float.parseFloat(amountText.getText().toString());

            // REFERNCES THE OTHER TEXT
            rateText.setText(Float.toString(price / amount));
        } else {
            rateText.setText("");
        }

        rateText.addTextChangedListener(rateTextListener);
    }

Upvotes: 0

Related Questions