我对TextWatcher有一个恼人的问题。我一直在网上搜索,但找不到任何东西。感谢有人可以帮助我。
出于某种原因,在一次文本更改时调用TextWatcher事件是不稳定的。有时它们会被触发一次(就像它们应该的那样),有时是两次,有时是3次。不知道为什么,整件事情非常直截了当。有时候,afterTextChanged()上的Editable参数会在toString()和length()中返回空值。
代码如下:
private TextWatcher mSearchAddressTextChangeListener = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) { }
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@Override
public void afterTextChanged(Editable searchedAddress) {
System.out.println("called multiple times.");
}
};
在afterTextChanged()
内(以及AsyncTask
)我不会对文字或EditText
视图进行任何更改。
我在Events of TextWatcher are being called twice中看到了问题,但即时通讯触发的事件多于(或少于)两次。
无论如何,感谢任何帮助。
编辑:我删除了afterTextChanged()的内容,导致即使没有我的代码也会出现此问题。是什么让我相信这是一个错误。当在常规字符(事件处理程序被触发两次)之后输入'space'字符时或者在删除常规字符之后的'space'字符(退格。事件处理程序被触发3次)时,会发生错误。帮助仍然会受到赞赏。
答案 0 :(得分:48)
我遇到了同样的问题,当我在连续文本的末尾用光标按下退格键时,afterTextChange被调用了3次: - 第一次使用正确的s值 - 第二次具有明确的价值 - 第三次再次使用正确的值
在网上搜索了很多内容之后,我尝试将EditText inputType更改为
android:inputType="textNoSuggestions"
不要问我为什么,但它有效,afterTextChanged现在只调用一次。
答案 1 :(得分:7)
根据TextWatcher的开发人员页面,如果对Editable
中的TextWatcher
进行了更改,则会触发对所有与TextWatchers
相关联的调用Editable
。现在,显然您的代码不会触发此行为。
但是,如果由于某种原因系统在TextWatcher
上有Editable
,很可能会出现您所描述的情况。 “为什么”,我听到你哭,“这应该发生吗?”
首先,经典辩护:没有理由不发生这种情况,严格来说,应该编写应用代码以使其具有弹性。
其次,我无法证明这一点,但我可以想象,处理EditText
中显示文本布局的代码使用TextWatcher
来处理更新文本的显示屏幕。此代码可能会将控制代码(未显示)插入Editable
以确保良好的换行符等。它甚至可以循环几次以使其正确,并且您可能只有在完成所有操作后才能进行第一次调用...
修改
根据@Learn OpenGL ES的评论,调用TextWatcher对于自动更正这样的事情是正常的。
答案 2 :(得分:3)
boolean isOnTextChanged = false;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
isOnTextChanged = true;
}
@Override
public void afterTextChanged(Editable quantity) {
if (isOnTextChanged) {
isOnTextChanged = false;
//dosomething
}
答案 3 :(得分:1)
inputBoxNumberEt.addTextChangedListener(new TextWatcher() {
boolean ignoreChange = false;
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (!ignoreChange) {
///Do your checks
ignoreChange = true;
inputBoxNumberEt.setText(string);
inputBoxNumberEt.setSelection(inputBoxNumberEt.getText().length());
ignoreChange = false;
}
}
});
答案 4 :(得分:1)
我尝试了在这个问题上回答的所有解决方案,但没有一个能为我工作。但经过一些搜索,我发现了this帖子。使用RxJava进行去抖动对我来说效果很好。这是我的最终解决方案:
在Gradle文件中添加RxJava依赖项:
compile 'io.reactivex:rxandroid:1.0.1'
compile 'io.reactivex:rxjava:1.0.14'
compile 'com.artemzin.rxjava:proguard-rules:1.0.14.2'
实施您的主题:
PublishSubject<String> yourSubject = PublishSubject.create();
yourSubject .debounce(100, TimeUnit.MILLISECONDS)
.onBackpressureLatest()
.subscribe(s -> {
//Implements anything you want
});
在TextWatcher中使用您的主题:
TextWatcher myTextWatcher = 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) {
yourSubject.onNext(s.toString()); //apply here your subject
}
@Override
public void afterTextChanged(Editable s) {
}
};
在EditText侦听器中添加TextWatcher:
my_edit_text.addTextChangedListener(myTextWatcher);
答案 5 :(得分:0)
对我来说,以下代码有效。请注意,在 afterTextChanged 方法中的 if 条件循环后,布尔值已更改
edittext.addTextChangedListener(new TextWatcher()
{
boolean considerChange = false;
public void beforeTextChanged(CharSequence cs, int start, int count, int after) {}
public void onTextChanged(CharSequence cs, int start, int before, int count) {}
public void afterTextChanged(Editable editable)
{
if (considerChange)
{
// your code here
}
considerChange = !considerChange; //see that boolean value is being changed after if loop
}
});
答案 6 :(得分:0)
我的问题与此有关,因为我在模拟器中运行我的应用程序并通过笔记本电脑的键盘打字(未使用模拟器的键盘),并且奇数输入将被复制。
这不是在物理设备上发生的。
根据上述Nico's的一些启示,这对我来说使输入文本更改仅触发一次是有效的。
添加了以下输入类型配置:
1)通过样式
<!-- in a style -->
<style name="My.Text.Style">
<item name="android:inputType">text|textMultiLine|textVisiblePassword</item>
</style>
,然后在xml中用作:
<EditText
android:id="@+id/my_edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/My.Text.Style"
/>
OR
2)直接进入xml
<EditText
android:id="@+id/my_edit_text"
android:inputType="text|textMultiLine|textVisiblePassword"
/>
这两种方法都应该很好,这种样式仅适合于希望在其他屏幕上重用它的情况。