Textwatcher giving Stackoverflow error

前端 未结 2 1081
心在旅途
心在旅途 2021-01-23 12:15

i am making a length converter which uses TextWatcher. the shortened code is

 v1.addTextChangedListener(new TextWatcher() {

         @Override
            publi         


        
相关标签:
2条回答
  • 2021-01-23 12:31

    Do not do setText inside onTextChanged(),it is causing recursion.

    You can try the following: Set a boolean variable when you do setText from inside the onTextChange(). This boolean variable will help to identify that onTextChange was called because text was change programmatically and not by the user,thus avoiding recursion

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                          if(isTextChangedByUser){
                              //calculate and set different values only when user has changed       values
                               editext.setText("programmatically setting the text,change the flag")
                               isTextChangedByUser=false;
                           }else{
                               //to avoid recursion
                                return;
                           }
            }
    

    Second time when onTextChanged is called it will simply return since isTextChangeByUser flag is false.In this manner we will avoid recursion.

    Alternatively,to make the implementation more simple you can put a "calculate" button next to each editext.You will only start calculation when the user presses this button and not when text changes.

    0 讨论(0)
  • 2021-01-23 12:43

    You are creating an infinite loop of Text Changes between v1 and v2.

    Whenever you edit something in v1, it's TextWatcher sets the text of v2 which in turn triggers the onTextChanged() of your v2's TextWatcher. Now, v2's TextWatcher sets text of v1 (which triggers the onTextChanged() of your v1 again). This is creating a never-ending loop and you are getting the StackOverflow exception.

    You have to change the flow of your code.

    EDIT: I am showing an example, how to get rid of the StackOverflow error for two EditText fields. You can follow the similar coding for as many EditTexts as you want.

    First of all, you can extend the TextWatcher like this (This will help you to keep your code organized. And, you can use this same TextWatcher for all your EditTexts):

    class MyInputWatcher implements TextWatcher {
            private EditText et;
    
            private MyInputWatcher(EditText editText) {
                et = editText;
            }
    
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
    
                switch (et.getId()) {
                case R.id.editText1: {
                    v2.removeTextChangedListener(watcher2);
                    v2.setText(s);// set whatever text you want to set in editText2
                    v2.addTextChangedListener(watcher2);
                    //add the above 3 lines of code for other EditTexts, too (if any)
                    break;
                }
                case R.id.editText2: {
                    v1.removeTextChangedListener(watcher1);
                    v1.setText(s); // set whatever text you want to set in editText1
                    v1.addTextChangedListener(watcher1);
    
                    break;
                }
                }
            }
    
            @Override
            public void afterTextChanged(Editable s) {
    
            }
        }
    

    The trick is to remove the onTextChangeListeners before you call setText(). And, then add them back after you are done with setting text.

    Declare these member variables:

    private EditText v1, v2;
    private MyInputWatcher watcher1, watcher2;
    

    Now, in the onCreate() method, implement this:

    v1 = (EditText)findViewById(R.id.editText1);
    v2 = (EditText)findViewById(R.id.editText2);
    
    watcher1 = new MyInputWatcher(v1);
    watcher2 = new MyInputWatcher(v2);
    
    v1.addTextChangedListener(watcher1);
    v2.addTextChangedListener(watcher2);
    

    For your convenience, the whole Activity class looks like this:

    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.EditText;
    
    public class MainActivity extends ActionBarActivity {
    
        EditText v1, v2;
        private MyInputWatcher watcher1, watcher2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            v1 = (EditText)findViewById(R.id.editText1);
            v2 = (EditText)findViewById(R.id.editText2);
    
            watcher1 = new MyInputWatcher(v1);
            watcher2 = new MyInputWatcher(v2);
    
            v1.addTextChangedListener(watcher1);
            v2.addTextChangedListener(watcher2);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        class MyInputWatcher implements TextWatcher {
            private EditText et;
    
            private MyInputWatcher(EditText editText) {
                et = editText;
            }
    
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
    
                switch (et.getId()) {
                case R.id.editText1: {
                    v2.removeTextChangedListener(watcher2);
                    v2.setText(s);// set whatever text you want to set in editText2
                    v2.addTextChangedListener(watcher2);
                    break;
                }
                case R.id.editText2: {
                    v1.removeTextChangedListener(watcher1);
                    v1.setText(s); // set whatever text you want to set in editText1
                    v1.addTextChangedListener(watcher1);
    
                    break;
                }
                }
            }
    
            @Override
            public void afterTextChanged(Editable s) {
    
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题