0

Goodevening everyone.

This is a continuous question from how to handle addTextChangedListener with three editText.

I have some problems in handling three EditTexts. The user can put in each of them a value, then it calculates other two values which are displayed in the other two EditTexts. When I try to type a value it crashes.

This is the code:

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) {

        }
    };

}

I found this code link, I think it could be helpful but I don't know how to implement it to my case.

Can you help me?

EDIT 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)
Community
  • 1
  • 1
Mark.
  • 49
  • 1
  • 12

2 Answers2

0

Try this: Note I don't know why this works, but I have had similar issues and this was what fixed it for me.

Do not declare your EditTexts globally. When you later call them it causes a crash. Instead, everytime you want to set the value, declare the EditText in the function.

So, inside frommMol, fromPercent, and frommg add these lines at the top of the function. Here's how you would do it for 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);
        }
    }
0

You stuck on infinite recursive, because your code causes such a cycle, like this:

  • If A changes, B will change
  • If B changes, C will change
  • If C changes, A will change
  • If A changes, B will change
  • ... and so on until the memory stack is full (StackOverflowError)

The better way to handle this is to check whether you really need to update other TextView. For example:

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("");
    }
}

By using condition if (!newText.equals(oldText)) you only update the TextView if it really needs to change, in order to cut the cycle we have explained above. It will be:

  • If A changes, B will change if B really needs to change
  • If B changes, C will change if C really needs to change
  • If C changes, A will change if A really needs to change

So there will be a point where the cycle stop.

You need to do this in other two EditTexts and adapt with your needs. This is just an example.

fikr4n
  • 3,250
  • 1
  • 25
  • 46
  • yes i thought the problem was the cycle but i didn't know how to fix it. – Mark. Feb 14 '17 at 01:47
  • can you explain me what did u do there in the last two lines? – Mark. Feb 14 '17 at 01:48
  • @Mark. as I said: "to check whether you really need to update other TextView". I am sorry if it's not clear, I'll update the answer. – fikr4n Feb 14 '17 at 01:55
  • I have some questions: 1. the "edit method (in your way)" will be also in the onTextChanged? 2. There is a way to delete what it's written in other views during i'm deleting value from one of them? – Mark. Feb 14 '17 at 01:56
  • @Mark. 1. You need to that in three of them as they depend each other; 2. Just delete it, for example, when the text is empty, just remember that call `setText` only if it is really needed to change. – fikr4n Feb 14 '17 at 02:07
  • it crashes if i use two addTextChangedListener – Mark. Feb 14 '17 at 02:08
  • @Mark. Try to change only `frommMol`, `fromPercent`, and `frommg` methods. I assume there are only 3 `addTextChangeListener`, one for each `EditText`, no more `removeTextChangeListener` and `addTextChangeListener` in the `fromXXX` methods. – fikr4n Feb 14 '17 at 02:11
  • yes i wrote them again the same way you did, deleting removetext and addText, wrote as you did and leave the rest as it was – Mark. Feb 14 '17 at 02:13
  • okay it's working, but not at all. It doesn't crash. But I can't delete a value: and this is right because, for example, if I wrote 12 it calculates other two values form the two EditTexts. Then I delete "2" and it calculates other values. Maybe I'm not so clear sorry, I hope you can understAnd the problem – Mark. Feb 14 '17 at 02:35
  • @Mark. You've had `if (!mgGlicText.isEmpty())`, just add `else` to make other empty when it's empty, don't forget to check **whether you really need to change the text** like before. – fikr4n Feb 14 '17 at 02:39
  • I changed the method as you did and added the else statement. The problem is I can't delete values. It is so strange – Mark. Feb 14 '17 at 02:49
  • it works perfectly just if I leave it in one editText – Mark. Feb 15 '17 at 00:50