问题描述
在一个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源代码中,发现一丝端倪。
在TextView的setText重载方法内部,存在如下调用:
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) {
}
});
}
问题解决。