【问题标题】:How to manage EditTexts and addTextChangedListener to avoid stack overflow如何管理 EditTexts 和 addTextChangedListener 以避免堆栈溢出
【发布时间】:2017-07-02 02:52:27
【问题描述】:

大家晚上好。

这是来自how to handle addTextChangedListener with three editText 的连续问题。

我在处理三个EditTexts 时遇到了一些问题。用户可以在其中的每一个中输入一个值,然后计算其他两个值,这些值显示在另外两个EditTexts 中。当我尝试输入一个值时它会崩溃。

这是代码:

public class MainActivity extends AppCompatActivity {

EditText Percent, mmolGlic, mgGlic;

double mmol = 0, mg = 0, perc = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Percent = (EditText) findViewById(R.id.percent);
    mmolGlic = (EditText) findViewById(R.id.mmol_glic);
    mgGlic = (EditText) findViewById(R.id.mg_glic);

 Percent.addTextChangedListener(percentWatcher);
        mmolGlic.addTextChangedListener(mmolGlicTextWatcher);
        mgGlic.addTextChangedListener(mgGlicWatcher);
}

 public void frommMol() {
        if (!mmolGlic.getText().toString().trim().isEmpty()) {
            mmol = Double.parseDouble(mmolGlic.getText().toString());
            perc = (mmol / 10.929) + 2.15;
            Percent.removeTextChangedListener(percentWatcher);
            Percent.setText(String.format("%.2f", perc));
            Percent.addTextChangedListener(percentWatcher);
        }
    }

    public void fromPercent() {
        if (!Percent.getText().toString().trim().isEmpty()) {
            perc = Double.parseDouble(Percent.getText().toString().trim());
            mmol = (perc - 2.15) * 10.929;
            mmolGlic.removeTextChangedListener(mmolGlicTextWatcher);
            mgGlic.removeTextChangedListener(mgGlicWatcher);
            mmolGlic.setText(String.format("%.2f", mmol));
            mg = (perc * 28.7) - 46.7;
            mgGlic.setText(String.format("%.2f", mg));
            mmolGlic.addTextChangedListener(mmolGlicTextWatcher);
            mgGlic.addTextChangedListener(mgGlicWatcher);
        }
    }

    public void frommg() {
        if (!mgGlic.getText().toString().trim().isEmpty()) {
            mg = Double.parseDouble(mgGlic.getText().toString());
            perc = (mg + 46.7) / 28.7;
            Percent.removeTextChangedListener(percentWatcher);
            Percent.setText(String.format("%.2f", perc));
            Percent.addTextChangedListener(percentWatcher);
        }
    }


    private TextWatcher percentWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            fromPercent();
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    };

    private TextWatcher mgGlicWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            frommg();
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    };

    private TextWatcher mmolGlicTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                frommMol();
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    };

}

我找到了这个code link,我认为它可能会有所帮助,但我不知道如何在我的情况下实施它。

你能帮帮我吗?

编辑 1:

FATAL EXCEPTION: main
    Process: com.example.marco.glicatest, PID: 3843
    java.lang.StackOverflowError: stack size 8MB
        at android.text.SpannableStringBuilder.getSpans(SpannableStringBuilder.java:819)
        at android.text.method.ReplacementTransformationMethod$SpannedReplacementCharSequence.getSpans(ReplacementTransformationMethod.java:184)
        at android.text.SpanSet.init(SpanSet.java:47)
        at android.text.TextLine.handleRun(TextLine.java:902)
        at android.text.TextLine.measureRun(TextLine.java:417)
        at android.text.TextLine.measure(TextLine.java:296)
        at android.text.TextLine.metrics(TextLine.java:270)
        at android.text.Layout.getLineExtent(Layout.java:1075)
        at android.text.Layout.getLineStartPos(Layout.java:565)
        at android.text.Layout.getHorizontal(Layout.java:938)
        at android.text.Layout.getHorizontal(Layout.java:907)
        at android.text.Layout.getPrimaryHorizontal(Layout.java:882)
        at android.text.Layout.getPrimaryHorizontal(Layout.java:872)
        at android.widget.TextView.getFocusedRect(TextView.java:5747)
        at android.view.FocusFinder.findNextFocus(FocusFinder.java:120)
        at android.view.FocusFinder.findNextFocus(FocusFinder.java:94)
        at android.view.FocusFinder.findNextFocus(FocusFinder.java:65)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:853)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.ViewGroup.focusSearch(ViewGroup.java:855)
        at android.view.View.focusSearch(View.java:8086)
        at android.widget.TextView.onCreateInputConnection(TextView.java:6283)
        at android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1177)
        at android.view.inputmethod.InputMethodManager.restartInput(InputMethodManager.java:1124)
        at android.widget.TextView.setText(TextView.java:4262)
        at android.widget.TextView.setText(TextView.java:4199)
        at android.widget.EditText.setText(EditText.java:84)
        at android.widget.TextView.setText(TextView.java:4174)
        at com.example.marco.glicatest.MainActivity.frommMol(MainActivity.java:44)
        at com.example.marco.glicatest.MainActivity$3.onTextChanged(MainActivity.java:141)
        at android.widget.TextView.sendOnTextChanged(TextView.java:7991)
        at android.widget.TextView.setText(TextView.java:4345)
        at android.widget.TextView.setText(TextView.java:4199)
        at android.widget.EditText.setText(EditText.java:84)
        at android.widget.TextView.setText(TextView.java:4174)
        at com.example.marco.glicatest.MainActivity.fromPercent(MainActivity.java:65)
        at com.example.marco.glicatest.MainActivity$1.onTextChanged(MainActivity.java:107)
        at android.widget.TextView.sendOnTextChanged(TextView.java:7991)
        at android.widget.TextView.setText(TextView.java:4345)
        at android.widget.TextView.setText(TextView.java:4199)
        at android.widget.EditText.setText(EditText.java:84)
        at android.widget.TextView.setText(TextView.java:4174)
        at com.example.marco.glicatest.MainActivity.frommMol(MainActivity.java:44)
        at com.example.marco.glicatest.MainActivity$3.onTextChanged(MainActivity.java:141)
        at android.widget.TextView.sendOnTextChanged(TextView.java:7991)
        at android.widget.TextView.setText(TextView.java:4345)
        at android.widget.TextView.setText(TextView.java:4199)
        at android.widget.EditText.setText(EditText.java:84)
        at android.widget.TextView.setText(TextView.java:4174)
        at com.example.marco.glicatest.MainActivity.fromPercent(MainActivity.java:65)
        at com.example.marco.glicatest.MainActivity$1.onTextChanged(MainActivity.java:107)
        at android.widget.TextView.sendOnTextChanged(TextView.java:7991)
        at android.widget.TextView.setText(TextView.java:4345)
        at android.widget.TextView.setText(TextView.java:4199)
        at android.widget.EditText.setText(EditText.java:84)
        at android.widget.TextView.setText(TextView.java:4174)
        at com.example.marco.glicatest.MainActivity.frommMol(Main

E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 9495276)
E/AndroidRuntime: Error reporting crash
               android.os.TransactionTooLargeException: data parcel size 9495276 bytes
           at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(Binder.java:503)
        at android.app.ActivityManagerProxy.handleApplicationCrash(ActivityManagerNative.java:4425)
        at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:90)
        at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
        at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)

【问题讨论】:

  • 请发布您崩溃时的堆栈跟踪
  • @GreyBeardedGeek 堆栈跟踪已添加

标签: android android-layout android-studio android-activity android-edittext


【解决方案1】:

您坚持无限递归,因为您的代码会导致这样的循环,如下所示:

  • 如果 A 改变,B 也会改变
  • 如果 B 改变,C 也会改变
  • 如果 C 改变,A 也会改变
  • 如果 A 改变,B 也会改变
  • ... 以此类推,直到内存堆栈已满 (StackOverflowError)

处理此问题的更好方法是检查您是否真的需要更新其他TextView。例如:

public void fromMg() {
    mgGlicText = mgGlic.getText().toString().trim();
    if (!mgGlicText.isEmpty()) {
        mg = Double.parseDouble(mgGlicText);
        perc = (mg + 46.7) / 28.7;
        // percent.removeTextChangedListener(percentWatcher); // not needed
        String newText = String.format("%.2f", perc);
        String oldText = percent.getText().toString();
        /* Check if the text is different, if so then change it */
        if (!newText.equals(oldText))
            percent.setText(newText);
        // percent.addTextChangedListener(percentWatcher); // not needed
    } else {
        if (percent.getText().length() > 0) // !percent.getText().toString().equals("")
            percent.setText("");
    }
}

通过使用条件if (!newText.equals(oldText)),您只有在确实需要更改时才更新TextView,以缩短我们上面解释的循环。它将是:

  • 如果A改变了,如果B真的需要改变,B就会改变
  • 如果B改变了,如果C真的需要改变,C就会改变
  • 如果C改变了,如果A真的需要改变,A就会改变

所以会有一个循环停止的点。

您需要在其他两个EditTexts 中执行此操作并根据您的需要进行调整。这只是一个例子。

【讨论】:

  • 是的,我认为问题出在循环上,但我不知道如何解决。
  • 你能解释一下你在最后两行做了什么吗?
  • @马克。正如我所说:“检查您是否真的需要更新其他 TextView”。如果不清楚,我很抱歉,我会更新答案。
  • 我有一些问题:1.“编辑方法(以你的方式)”也会在onTextChanged中吗? 2.在我从其中一个视图中删除值的过程中,有一种方法可以删除它在其他视图中写入的内容?
  • @马克。 1.你需要在他们三个,因为他们相互依赖; 2.直接删掉就好了,比如文本为空的时候,记得在真的需要改的时候才调用setText
【解决方案2】:

试试这个:注意我不知道为什么会这样,但我也遇到过类似的问题,这就是为我解决的问题。

不要在全局范围内声明您的 EditTexts。当您稍后调用它们时,它会导致崩溃。相反,每次要设置值时,请在函数中声明 EditText。

因此,在 frommMol、fromPercent 和 frommg 内部,将这些行添加到函数的顶部。以下是您对 fromPercent 的处理方式:

public void fromPercent() {
        EditText Percent = (EditText) findViewById(R.id.percent);
        EditText mmolGlic = (EditText) findViewById(R.id.mmol_glic);
        EditText mgGlic = (EditText) findViewById(R.id.mg_glic);
        if (!Percent.getText().toString().trim().isEmpty()) {
            perc = Double.parseDouble(Percent.getText().toString().trim());
            mmol = (perc - 2.15) * 10.929;
            mmolGlic.removeTextChangedListener(mmolGlicTextWatcher);
            mgGlic.removeTextChangedListener(mgGlicWatcher);
            mmolGlic.setText(String.format("%.2f", mmol));
            mg = (perc * 28.7) - 46.7;
            mgGlic.setText(String.format("%.2f", mg));
            mmolGlic.addTextChangedListener(mmolGlicTextWatcher);
            mgGlic.addTextChangedListener(mgGlicWatcher);
        }
    }

【讨论】:

  • 我应该对每种方法都这样做吗?
  • 是的,试试看是否能解决问题。如果是,请接受这个作为正确答案!
猜你喜欢
  • 2010-11-30
  • 2020-03-08
  • 2011-09-21
  • 2014-04-13
  • 2013-10-29
  • 1970-01-01
  • 2012-08-22
  • 2011-11-23
  • 2010-12-04
相关资源
最近更新 更多