重写TextWatcher监听方法onTextChanged,调用EditText.setText死循环问题解决方案

问题描述

在一个EditText控件中,监听文字变化状态,使用了TextWatcher中的onTextChanged方法,大抵如下:

	input.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) {
                input.setText(/*对字符串s进行相关处理*/);
            }

            @Override
            public void afterTextChanged(Editable s) {
                
            }
        });
    }

结果导致了无限死循环,且字符串s被不断地循环复制,越来越长,APP随之崩溃。

问题解决

看了一下TextWatcher的OnTextChanged方法,这只是个接口的抽象方法,Google官方的文档中并没有给出太多介绍。

然后从setText源代码中,发现一丝端倪。

TextViewsetText重载方法内部,存在如下调用:


private void setText(CharSequence text, BufferType type,
                         boolean notifyBefore, int oldlen) {
	...
	sendOnTextChanged(text, 0, oldlen, textLength);
    onTextChanged(text, 0, oldlen, textLength);
    ...
}

这个sendOnTextChanged 方法内部,调用了TextWatcher接口的onTextChanged方法(TextView保持了一个TextWatcher接口作为私有成员)

/** * Not private so it can be called from an inner class without going * through a thunk. */
    void sendOnTextChanged(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).onTextChanged(text, start, before, after);
            }
        }

        if (mEditor != null) mEditor.sendOnTextChanged(start, before, after);
}

所以如果实现了onTextChanged方法 ,且在该方法中执行了setText,显然形成了一个死循环。因此,在执行setText方法之前,先要解除onTextChanged方法 的实现,解决方案如下:

	input.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) {
                // 移除监听
                input.removeTextChangedListener(this);
                ...
                input.setText(/*对字符串s进行相关处理*/);
                ...
                // 重新注册监听,使用this,再次指向该实现
                input.addTextChangedListener(this);
            }

            @Override
            public void afterTextChanged(Editable s) {
                
            }
        });
    }

问题解决。

点赞