使用RxBinding实现addTextChangedListener以进行基于货币的计算

时间:2016-05-17 10:34:36

标签: android android-edittext rx-java reactive-programming observable

我有一个编辑文本视图,用于计算与货币相关的内容。 编辑文本从0.00开始 这是出于计费目的,其中供应商输入要向客户收取的账单金额。用户只能在编辑文本框中输入0-9的数字。

如果用户输入1,则变为0.01
如果用户输入2,则变为0.12,依此类推

这是我与TextWatcher一起使用的代码,它运行得很好。

etInitialOtherBill.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) {
                if(!s.toString().equals(currentO) && !s.toString().equals("")){
                    etInitialOtherBill.removeTextChangedListener(this);
                    String cleanString = s.toString().replace(".", "");
                    double parsed = Double.parseDouble(cleanString);
                    String formatted = NumberFormat.getCurrencyInstance().format((parsed/100));
                    currentO = formatted.replace(NumberFormat.getCurrencyInstance().getCurrency().getSymbol(),"");
                    //new
                    currentO=currentO.replace("\u00A0","").replace(",","");
                    etInitialOtherBill.setText(currentO);
                    etInitialOtherBill.setSelection(currentO.length());
                    etInitialOtherBill.addTextChangedListener(this);
                }
            }
            @Override
            public void afterTextChanged(Editable s) {
                Double initialMBill, initialOBill;
                if (etInitialMedicineBill.getText().toString().equals("") || etInitialMedicineBill.getText().toString().equals(".")){
                    initialMBill=0.00;
                }else {
                    initialMBill= Double.valueOf(etInitialMedicineBill.getText().toString());
                }
                if (etInitialOtherBill.getText().toString().equals("") || etInitialOtherBill.getText().toString().equals(".")){
                    initialOBill=0.00;
                }else {
                    initialOBill= Double.valueOf(etInitialOtherBill.getText().toString());
                }
                Double discountM =Math.round( initialMBill * 100.0 *discountToConsumer ) / 100.0;
                Double netMBill = Math.round( initialMBill * 100.0 *amountPayable ) / 100.0;
                Double finalBill = netMBill+initialOBill;
                tvDiscountMedicine.setText(df2.format(discountM));
                tvNetMedicineBill.setText(df2.format(netMBill));
                tvFinalBill.setText(df2.format(finalBill));
            }
        });

afterTextChanged是执行一些计算并在TextView

中显示

目前我尝试的是

                RxTextView.textChanges(editText)
                .map(new Func1<CharSequence, CharSequence>() {
                    @Override
                    public CharSequence call(CharSequence charSequence) {
                        //perform calculations as in onTextChanged
                        //This causes the infinite loop. Adding if statements did not solve my problem either
                        return someValue
                    }
                })
                .subscribe(new Action1<CharSequence>() {
                    @Override
                    public void call(CharSequence charSequence) {
                        //If user inputs a number which was formatted, then display it
                        editText.setText(charSequence);
                        editText.setSelection(charSequence.length()
                    }
                });

现在,这将代码置于无限循环中,removeTextChangedListener(this)避免了这种情况。我曾尝试使用subscription.unsubscribe(),但这并没有让我任何地方。

我正在寻找一些指导,我可以再次尝试这一点。

2 个答案:

答案 0 :(得分:0)

您可以尝试创建自己的CustomEditText,并在下面的代码中实现想要的行为。我希望这有帮助

public class CustomEditText extends EditText{

    List<TextWatcher> textWatchers = new ArrayList<>();
    private TextWatcher watcher;

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void addTextChangedListener(TextWatcher watcher) {
        textWatchers.add(watcher);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        if (watcher == null) {
            watcher= new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    for (TextWatcher watcher : textWatchers) {
                        watcher.beforeTextChanged(s, start, count, after);
                    }

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    for (TextWatcher watcher : textWatchers) {
                        watcher.onTextChanged(s, start, before, count);
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {
                    for (TextWatcher watcher : textWatchers) {
                        watcher.afterTextChanged(s);
                    }
                }
            };
        }

        super.removeTextChangedListener(watcher);
        super.setText(text, type);
        super.addTextChangedListener(watcher);
    }
}

MainActivity

    final CustomEditText editText = (CustomEditText) findViewById(R.id.custom_edit_text);
    RxTextView.textChanges(editText)
            .map(new Func1<CharSequence, CharSequence>() {
                @Override
                public CharSequence call(CharSequence charSequence) {
                    return charSequence;
                }
            })
            .subscribe(new Action1<CharSequence>() {
                @Override
                public void call(CharSequence charSequence) {
                    Log.d(TAG, "call: Check infinite loop");
                    editText.setText(charSequence + " " + charSequence.length());
                    editText.setSelection(charSequence.length());
                }
            });

答案 1 :(得分:0)

更短,但是hacky解决方案。

    { 
    ConnectableObservable<TextViewTextChangeEvent> onTextChanges = 

    RxTextView.textChangeEvents(textView).publish();

    onTextChanges
            .filter(event -> isUser(event.view()))
            .map(this::changeProps)
            .subscribe(event -> {
                textView.setTag(Source.APP);
                setTextProps(textView, event);
            });

    onTextChanges.filter(event -> isApp(event.view()))
            .delay(1, TimeUnit.MILLISECONDS).subscribe(event -> {
        event.view().setTag(Source.USER);
    });

    onTextChanges.connect();
 }

 private boolean isApp(View view) {
    return view.getTag() == null || Source.APP.equals(view.getTag());
 }

 private boolean isUser(View view) {
     return Source.USER.equals(view.getTag());
 }

 private static final class Source {
    public static final String APP = "APP";
    public static final String USER = "USER";
}