2

Currently, I need to capture the final appeared text in EditText.

Here's my simple code.

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        EditText editText = findViewById(R.id.edit_text);

        editText.addTextChangedListener(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) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                Log.i("CHEOK", ">>>" + editable.toString() + "<<<");
                doSomething(editable.toString());
            }

            private void doSomething() {}
        });
    }
}

activity_main.xml

<EditText
    android:id="@+id/edit_text"

    android:layout_width="match_parent"
    android:layout_height="wrap_content"

    android:inputType="textMultiLine|textNoSuggestions"

    android:imeOptions="actionSend" />

Here's how it behave.

When there's no spelling suggestion

enter image description here

When I press ENTER

enter image description here

afterTextChanged is being triggered one time with the following output.

>>>123
456<<<

When spelling suggestion is there

enter image description here

When I press ENTER

enter image description here

afterTextChanged is being triggered multiple time with the following output.

>>>def<<<
>>><<<
>>>abc
<<<
>>>abc
def<<<

I'm not interested the intermediate text in between. I'm only interested in final text (which is abc\ndef)

How possible can I have something like

@Override
public void afterTextChanged(Editable editable) {
    if (isFinalText(edittable.toString())) {
        doSomething(editable.toString());
    }
}

without turning off spelling suggestion.

P/S

I don't mind to extends EditText, and do some hacking within it. However, I had tried to override dispatchKeyEvent and onKeyPreIme in EditText. Not sure why they are not being called.

P/S/S

I'm also try onEditorAction technique as discussed in https://stackoverflow.com/a/8063533/72437 It won't work for my case as my EditText is multi-line.

Cheok Yan Cheng
  • 49,649
  • 117
  • 410
  • 768
  • i think you can't , moreover for different keyboards you will get different intermediate state. The only way out is to unregister the text watcher in after text change. Set your text and then again register the textwatcher – Gautam Mar 23 '18 at 06:21

2 Answers2

0

Finally I come to the conclusion :

editText.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 (prevString.length() >= s.length()) {
                if (userIsInteracting) {
                    doSomething(s.toString());
                }
            } else {
                doSomething(s.toString());
            }
            prevString = s.toString();
        }
    });
 editText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL)
                    userIsInteracting = true;
                Log.d("key event", keyCode + event.toString());
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        userIsInteracting = false;
                    }
                }, 1000);
                return false;
            }
        });

Do try it out, It will work for sure. I tried and working perfectly. Happy Coding!!!

NilayDani
  • 876
  • 6
  • 23
0

This is a correct solution to solve my faced problem. The key is to use

editText.post

Solution

public class MainActivity extends AppCompatActivity {

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

        final EditText editText = findViewById(R.id.edit_text);

        editText.addTextChangedListener(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) {

            }

            @Override
            public void afterTextChanged(final Editable editable) {
                final String originalString = editable.toString();

                editText.post(new Runnable() {
                    @Override
                    public void run() {
                        String text = editText.getText().toString();
                        if (text.equals(originalString)) {
                            Log.i("CHEOK", originalString);
                        }
                    }
                });
            }
        });
    }
}

The idea is, when the time posted function is executed, editText.getText() is returning a complete text (abc\ndef)

Adding if (text.equals(originalString)), is to ignore 2 intermediate texts in between (def and abc\n)

Cheok Yan Cheng
  • 49,649
  • 117
  • 410
  • 768
  • I didn't get this. What you describe in your question is not resolved in this. Please can you explain this? – NilayDani Mar 24 '18 at 07:14