Maulik Dodia
Maulik Dodia

Reputation: 1659

Android: RxTextView.textChanges for EditText goes infinite loop

What I need: I want to observe change in EditText and format in some number DecimalFormat.

What I'm Trying: I'm trying to observe EditText with Rx.

What's the Issue: After I start typing it goes to INFINITE loop. Below is the code what I'm trying to do.

ProductDetailsActivity.java:

public class ProductDetailsActivity extends AppCompatActivity {    
    @BindView(R.id.et_product_price)
    EditText et_product_price;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_product_details);

        ButterKnife.bind(this);

        RxTextView.textChanges(et_product_price)
            .skipInitialValue()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(str -> {

                double amount = Double.parseDouble(str.toString());
                DecimalFormat formatter = new DecimalFormat("#,##,###");
                String formatted = formatter.format(amount);
                et_product_price.setText(formatted);

                Log.e("mk", "output: " + formatted);

            }, throwable -> {
                Log.e("mk", "Error: " + throwable.getMessage());
            });
    }
}

Upvotes: 0

Views: 1034

Answers (2)

Maulik Dodia
Maulik Dodia

Reputation: 1659

Finally I went back to TextWatcher to get the solution. I wrote in onCreate method like below.

et_product_price.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 (!TextUtils.isEmpty(s)) {

                String enteredProductPrice = s.toString().replace(",", "");

                double enteredProductPriceDouble = Double.parseDouble(enteredProductPrice);
                String formattedProductPrice = new DecimalFormat("#,##,###").format(enteredProductPriceDouble);

                et_product_price.removeTextChangedListener(this);

                et_product_price.setText(formattedProductPrice);
                et_product_price.setSelection(et_product_price.getText().length());

                et_product_price.addTextChangedListener(this);
            }
        }
    });

This might help somebody.

Upvotes: 2

Ben P.
Ben P.

Reputation: 54204

Every time you call setText(), even if the actual text isn't different, that will count as a "text changed" event. That means this line is the culprit:

et_product_price.setText(formatted);

When you call that for the first time, it will trigger a text change event, so your subscriber will be triggered again. It will parse and format the double, and then call setText() again. And so on.

There are many ways to solve this, but fundamentally you just need to make sure that you don't call setText() if the "new" value is equal to the "old" value.

if (!formatted.equals(et_product_price.getText().toString()) {
    et_product_price.setText(formatted);
}

Upvotes: -1

Related Questions