How to use InputConnectionWrapper?

2019-03-27 08:37发布

问题:

I have an EditText. Now I want to get all changes made by the user to this EditText and work with them before manually inserting them into the EditText. I don't want the user to directly change the text in the EditText. This should only be done by my code (e.g. by using replace() or setText()).

I searched a bit and found an interesting class named InputConnectionWrapper. According to the javadoc it shall act as a proxy for a given InputConnection. So I subclassed it like this:

private class EditTextInputConnection extends InputConnectionWrapper {

    public EditTextInputConnection(InputConnection target, boolean mutable) {
        super(target, mutable);
    }

    @Override
    public boolean commitText(CharSequence text, int newCursorPosition) {
                    // some code which takes the input and manipulates it and calls editText.getText().replace() afterwards
        return true;
    }

}

To initialize the wrapper I overwrote the following method in my EditText-subclass:

public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    InputConnection con = super.onCreateInputConnection(outAttrs);
    EditTextInputConnection connectionWrapper = new EditTextInputConnection(con, true);
    return connectionWrapper;
}

However, commitText() never gets called. The onCreateInputConnection() gets called and the constructor of EditTextInputConnection also, but never commitText(), altough it should be, when I enter some text into the field. At least, that's how I understand the usage of InputConnectionWrapper. Or am I wrong?

Edit: It seems, that commitText() is only called for special characters like "."," " etc. As I understand the Android sourcecode for all other characters InputConnectionWrapper.sendKeyEvent() should be called, but that's not the case... I'm absolutely stuck at this point. I already tried EditText.onKeyPreIme(), but this only works on hardware keyboards. So that's no alternative... I don't really understand, why Android handles soft keyboards that different from hardware keyboards. EditText.onTextChanged() gets also fired on non-user input, so this is also not, what I'm looking for.

回答1:

It turned out, that the above usage of the InputConnectionWrapper was totally correct. However, commitText() gets never called (except for special cases), as there are other methods, which are used during typing. These are mainly setComposingText() and sendKeyEvent(). However, it is also important to overwrite seldom used methods like deleteSurroundingText() or commitText() to make sure to catch every user input.



回答2:

Blundell suggested on the chat that you use a TextWatcher. Check if this helps you out.



回答3:

Use a TextWatcher, disconnect it when you're modifying your edittext and reconnect it when done. This way, you won't trigger infinite calls.