50

我对 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

我看到在TextWatcher 的事件中提出的问题被调用了两次,但我触发的事件多于(或少于)两次。

无论如何,感谢任何帮助。

编辑:我删除了 afterTextChanged() 的内容,因为即使没有我的代码,这个问题也会发生。是什么让我相信这是一个错误。当在常规字符后立即输入“空格”字符(触发事件处理程序两次)或删除常规字符后的“空格”字符(退格键。事件处理程序被触发 3 次)时,会发生该错误。帮助仍将不胜感激。

4

8 回答 8

59

我遇到了同样的问题,当我在连续文本的末尾用光标按下退格键时, afterTextChange 被调用了 3 次: - 第一次使用正确的 s 值 - 第二次使用明确的值 - 第三次使用再次正确的值

在网上搜索了很多之后,我尝试将我的 EditText inputType 更改为

android:inputType="textNoSuggestions"

不要问我为什么,但它起作用了,afterTextChanged 现在只被调用一次。

于 2013-10-10T14:29:57.400 回答
9
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
    }
于 2017-04-07T09:37:52.137 回答
8

根据TextWatcherEditable的开发人员页面,如果对内部进行更改TextWatcher,它将触发对所有TextWatchers链接到该内部的进一步调用Editable。现在,显然您的代码不会触发此行为。

但是,如果由于某种原因,系统具有TextWatcheron the Editable,则很有可能会发生您描述的情况。“为什么”,我听到你哭了,“这应该发生吗?”

首先,经典的防御:它没有理由不发生,严格来说,应用程序代码应该被编写成能够适应它。

其次,我无法证明这一点,但我可以很好地想象处理 an 内显示文本布局的代码EditText使用 aTextWatcher来处理更新屏幕上文本的显示。此代码可能会在 中插入控制代码(未显示)Editable以确保良好的换行符等。它甚至可能会循环几次以使其正确,并且您可能只有在完成所有操作后才能接到第一个电话...

编辑

根据@Learn OpenGL ES 的评论,对于自动更正之类的事情,调用 TextWatcher 是正常的。

于 2013-08-18T17:32:40.163 回答
4

我尝试了关于这个问题的所有解决方案,但没有一个对我有用。但经过一番搜索,我找到了这篇文章。使用 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);
于 2018-03-20T12:44:13.960 回答
3

您可以使用布尔检查,例如:

    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;
            }
        }
    });
于 2016-03-03T14:16:53.870 回答
2

对我来说,下面的代码有效。请注意,在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
            }


        });
于 2019-04-26T18:06:01.583 回答
0

我的问题与此有关,因为我在模拟器中运行我的应用程序并通过笔记本电脑的键盘打字(不使用模拟器的键盘)并且奇怪的输入会被重复。

这在物理设备中没有发生。

从上面Nico 的回答中得到一些启发,这对我来说是让输入文本更改只被触发一次。

添加了以下输入类型配置:

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"
   />

或者

2)直接进入xml

<EditText
   android:id="@+id/my_edit_text"
   android:inputType="text|textMultiLine|textVisiblePassword"
   />

两种方法都应该没问题,这种风格只是为了在其他屏幕上重用它的情况。

于 2020-03-25T13:15:43.763 回答
0

假设每个字符的打字速度为 300 毫秒。

    private var textDispatcherHandler = Handler(Looper.getMainLooper())
    private var textDispatcherRunnable:Runnable? = null

    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        if(p0!=null){
            dispatchTextToFilter(p0.toString())
        }
    }
    
    private fun dispatchTextToFilter(string: String){
        if(textDispatcherRunnable!=null){
            textDispatcherHandler.removeCallbacks(textDispatcherRunnable!!)
        }
    
        if(textDispatcherRunnable==null){
            textDispatcherRunnable = Runnable {
                //doSomething here
            }
        }
        textDispatcherHandler.postDelayed(textDispatcherRunnable!!,300)
    }
于 2021-08-27T08:58:52.113 回答