textwatcher上的IndexOutOfBoundsException

时间:2015-10-08 09:22:27

标签: android textwatcher

我正在使用textwatcher来检查用户输入的有效性。我的一些用户遇到了这个textwacher引起的崩溃。这是google提供的堆栈跟踪:

java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1

at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at android.widget.TextView.sendAfterTextChanged(TextView.java:7997)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:10043)
at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:970)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:497)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:435)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:30)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:679)
at android.view.inputmethod.BaseInputConnection.setComposingText(BaseInputConnection.java:437)
at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:333)
at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:77)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)

我的代码:

        Zipcode.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) {
                if (editable.toString().equals(zc)) return;
                zc = editable.toString();
                isZipcodeChecked = false;
                Log.d(TAG, "Text changed : " + editable.toString());
                if (editable.toString().length() != 5) {
                    Zipcode.setTextColor(Color.RED);
                    return;
                }
                checkZipcode(editable.toString());
            }
        });

我没有更多关于这是如何发生的信息。它大部分时间都可以正常工作,我无法重现这个bug。对发生了什么有什么想法吗?

2 个答案:

答案 0 :(得分:5)

答案已在评论中给出,但很难看出你是否只是像我一样。所以真正的答案是:

避免两次或多次添加TextWatcher,因为第一次将编辑内容,后续的内容将导致异常。

由于无法检查EditText是否已经设置了TextWatcher,因此我使用布尔值构建了自己的解决方案,检查是否已添加TextWatcher。

private EditText mEditText;
private TextWatcher mTextWatcher;
private boolean mTextWatcherIsEnabled = false;

public void setTextWatcher(TextWatcher textWatcher) {
    mTextWatcher = textWatcher;
}

public void enableTextWatcher() {
    if (!mTextWatcherIsEnabled) {
        mEditText.addTextChangedListener(mTextWatcher);
    }
    mTextWatcherIsEnabled = true;
}

public void disableTextWatcher() {
    if (mTextWatcherIsEnabled) {
        mEditText.removeTextChangedListener(mTextWatcher);
    }
    mTextWatcherIsEnabled = false;
}

答案 1 :(得分:3)

发生这种情况是因为我在同一个视图中添加了两个不同的TextWatcher,而我首先添加的是删除自身:

view.addTextChangedListener(new ListenerA());
view.addTextChangedListener(new ListenerB());
class ListenerA extends TextWatcher {

    @Override
    public void beforeTextChanged(CharSequence s, int i, int i1, int i2) {
        view.removeTextChangedListener(this);
        // ...
    }
}

由于 first 会自行删除,因此会导致索引超出范围的异常:

private void sendBeforeTextChanged(CharSequence text, int start, int before, int after) {
    if (mListeners != null) {
        final ArrayList<TextWatcher> list = mListeners;
        final int count = list.size();
        for (int i = 0; i < count; i++) {
            list.get(i).beforeTextChanged(text, start, before, after);
        }
    }
    // ...
}
查询

count,列表大小为2。因此它调用get(0),然后将其自身删除。然后它调用get(1),但是列表大小现在仅为1,因此引发了异常。

我解决了这个问题,首先没有实际删除TextWatcher,而是禁用了行为。您也可以通过保证只有列表中的最后一个观察者将其自身删除,来解决此问题。