在EditText中更改文本后0.5秒,我该怎么办?

Bob*_*obs 59 android filter textwatcher textchanged android-edittext

我正在使用EditText过滤我的列表.我想在用户输入EditText后0.5秒过滤列表.我为此目的使用了这个afterTextChanged事件TextWatcher.但是,对于EditText中的每个字符更改,此事件都会增加.

我该怎么办?

Ber*_*ťák 145

editText.addTextChangedListener(
    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) { }

        private Timer timer=new Timer();
        private final long DELAY = 1000; // milliseconds

        @Override
        public void afterTextChanged(final Editable s) {
            timer.cancel();
            timer = new Timer();
            timer.schedule(
                new TimerTask() {
                    @Override
                    public void run() {
                        // TODO: do what you need here (refresh list)
                        // you will probably need to use runOnUiThread(Runnable action) for some specific actions
                    }
                }, 
                DELAY
            );
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

Timer当文本输入EditText发生变化时,诀窍在于每次取消和重新安排.祝好运!

更新 对于有兴趣设置延迟时间的人,请参阅此文章.

  • 检查一次,http://stackoverflow.com/questions/10217051/how-to-avoid-multiple-triggers-on-edittext-while-user-is-typing (2认同)

Naz*_*arK 45

最好使用Handler和postDelayed()方法.在android的实现中,Timer每次都会创建新线程来运行任务.然而,Handler有自己的Looper可以连接到我们想要的任何线程,因此我们不会支付额外的费用来创建线程.

 Handler handler = new Handler(Looper.getMainLooper() /*UI thread*/);
 Runnable workRunnable;
 @Override public void afterTextChanged(Editable s) {
    handler.removeCallbacks(workRunnable);
    workRunnable = () -> doSmth(s.toString());
    handler.postDelayed(workRunnable, 500 /*delay*/);
 }

 private final void doSmth(String str) {
    //
 }
Run Code Online (Sandbox Code Playgroud)


小智 13

您可以使用RxBindings,这是最好的解决方案.请参阅RxJava操作员debounce指南,我相信在您的情况下会做得很好.

RxTextView.textChanges(editTextVariableName)
            .debounce(500, TimeUnit.MILLISECONDS)
            .subscribe(new Action1<String>() {
                @Override
                public void call(String value) {
                    // do some work with the updated text
                }
            });
Run Code Online (Sandbox Code Playgroud)

http://reactivex.io/documentation/operators/debounce.html


小智 11

使用 Kotlin 扩展函数和协程:

fun AppCompatEditText.afterTextChangedDebounce(delayMillis: Long, input: (String) -> Unit) {
    var lastInput = ""
    var debounceJob: Job? = null
    val uiScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
    this.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            if (editable != null) {
                val newtInput = editable.toString()
                debounceJob?.cancel()
                if (lastInput != newtInput) {
                    lastInput = newtInput
                    debounceJob = uiScope.launch {
                        delay(delayMillis)
                        if (lastInput == newtInput) {
                            input(newtInput)
                        }
                    }
                }
            }
        }

        override fun beforeTextChanged(cs: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(cs: CharSequence?, start: Int, before: Int, count: Int) {}
})}
Run Code Online (Sandbox Code Playgroud)


Bee*_*emo 9

没有上述解决方案适合我.

我需要一种方法让TextWatcher不会触发我在搜索视图中输入的每个字符并显示一些进度,这意味着我需要访问UI线程.

private final TextWatcher textWatcherSearchListener = new TextWatcher() {
    final android.os.Handler handler = new android.os.Handler();
    Runnable runnable;

    public void onTextChanged(final CharSequence s, int start, final int before, int count) {
        handler.removeCallbacks(runnable);
    }

    @Override
    public void afterTextChanged(final Editable s) {
        //show some progress, because you can access UI here
        runnable = new Runnable() {
            @Override
            public void run() {
                //do some work with s.toString()
            }
        };
        handler.postDelayed(runnable, 500);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
};
Run Code Online (Sandbox Code Playgroud)

在每个onTextChanged上删除Handler(在用户输入新字符时调用).在输入字段内更改文本之后调用afterTextChanged,我们可以在其中启动新的Runnable,但如果用户输入更多字符,将取消它(有关更多信息,调用这些回调时,请参阅此内容).如果用户不再输入字符,则间隔将在postDelayed中传递,并且它将调用您应该对该文本执行的工作.

此代码每个间隔仅运行一次,而不是每个关键用户输入.希望它能帮助将来的某个人.


And*_*Dev 7

在 Kotlin 语言中,你可以这样做:

tv_search.addTextChangedListener(mTextWatcher)

private val mTextWatcher: TextWatcher = object : TextWatcher {
    private var timer = Timer()
    private val DELAY: Long = 1000L

    override fun afterTextChanged(s: Editable?) {
        timer.cancel()
        timer = Timer()
        timer.schedule(object : TimerTask() {
            override fun run() {

                // Do your stuff here
            }
        }, DELAY)
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    }

}
Run Code Online (Sandbox Code Playgroud)


Vah*_*yan 5

观察文本更改事件的另一种方法是使用协程通道。

lifecycleScope.launchWhenCreated {
            editText.afterTextChanged {
                // do something
            }
        }
Run Code Online (Sandbox Code Playgroud)

创建扩展函数以从流中收集数据

suspend fun EditText.afterTextChanged(afterTextChanged: suspend (String) -> Unit) {
    val watcher = Watcher()
    this.addTextChangedListener(watcher)

    watcher.asFlow()
        .debounce(500)
        .collect { afterTextChanged(it) }
}
Run Code Online (Sandbox Code Playgroud)

创建一个 Watcher 类以在更改后提供文本

class Watcher : TextWatcher {

    private val channel = ConflatedBroadcastChannel<String>()

    override fun afterTextChanged(editable: Editable?) {
        channel.offer(editable.toString())
    }

    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}

    fun asFlow(): Flow<String> {
        return channel.asFlow()
    }
}
Run Code Online (Sandbox Code Playgroud)