web-dev-qa-db-ja.com

EditTextでテキストが変更されてから0.5秒後に、どうすればよいですか?

EditTextを使用してリストをフィルタリングしています。リストをフィルタリングしたいユーザーがEditTextの入力を完了してから0.5秒後。この目的でafterTextChangedTextWatcherイベントを使用しました。ただし、このイベントは、EditTextで文字が変更されるたびに発生します。

私は何をすべきか?

57
Bobs
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
            );
        }
    }
);

トリックは、Timerのテキストが変更されるたびにEditTextをキャンセルして再スケジュールすることです。がんばろう!

[〜#〜] update [〜#〜]遅延を設定する時間に興味がある人は、 この投稿 を参照してください。

138
Berťák

PostDelayed()メソッドでHandlerをより適切に使用します。 Androidの実装では、タイマーはタスクを実行するたびに新しいスレッドを作成します。ただし、ハンドラーには、必要なスレッドに接続できる独自のルーパーがあります。そのため、スレッドを作成するために余分な費用はかかりません。

 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) {
    //
 }
43
NazarK

RxBindings を使用できます。これが最適なソリューションです。 RxJavaオペレーターのデバウンスのガイドを参照してください。それはあなたのケースでうまくいくと確信しています。

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

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

11
Anton Makhrov

上記のソリューションのどれも私にとってはうまくいきませんでした。

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) {}
};

すべてのonTextChangedでハンドラーを削除します(ユーザーが新しい文字を入力すると呼び出されます)。 afterTextChangedは、新しいRunnableを開始できる入力フィールド内でテキストが変更された後に呼び出されますが、ユーザーがさらに文字を入力するとキャンセルされます(詳細については、これらのコールバックが呼び出されると、 こちらを参照 )。ユーザーがもう文字を入力しない場合、intervalはpostDelayedに渡され、そのテキストで行うべき作業を呼び出します。

このコードは、すべての主要なユーザー入力に対してではなく、間隔ごとに1回だけ実行されます。それが将来誰かを助けることを願っています。

9
Beemo

書き込みが終了したことをどのように判断しますか?編集テキストがフォーカスを失うことはありますか?次に、 setOnFocusChangedListener があります。

問題の最新の編集への応答:最新のキーストロークの後、特定の時間待機したい場合は、最初にスレッドを起動する必要がありますキーを押します(TextWatcherを使用)。常に最新のキーストロークの時間を登録します。スレッドを、最新のキーストロークの時間+ 0.5秒までスリープさせます。最新のキーストロークのタイムスタンプが更新されていない場合は、意図したとおりに実行してください。

4
pgsandstrom

TextWatcherインターフェイスを使用し、それを実装するカスタムクラスを作成して、CustomTextWatcherを何度も再利用できます。また、ビューやコンストラクタに必要なものを渡すことができます。 :

public abstract class CustomTextWatcher implements TextWatcher { //Notice abstract class so we leave abstract method textWasChanged() for implementing class to define it

    private final TextView myTextView; //Remember EditText is a TextView so this works for EditText also


    public AddressTextWatcher(TextView tView) { //Notice I'm passing a view at the constructor, but you can pass other variables or whatever you need
        myTextView= tView;

    }

    private Timer timer = new Timer();
    private final int DELAY = 500; //milliseconds of delay for timer

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(final Editable s) {
        timer.cancel();
        timer = new Timer();

        timer.schedule(

                new TimerTask() {
                    @Override
                    public void run() {
                        textWasChanged();
                    }
                },
                DELAY

        );
    }

    public abstract void textWasChanged(); //Notice abstract method to leave implementation to implementing class

}

これで、アクティビティで次のように使用できます。

    myEditText.addTextChangedListener(new CustomTextWatcher(myEditText) { //Notice I'm passing in constructor of CustomTextWatcher myEditText I needed to use
        @Override
        public void textWasChanged() {
            //doSomething(); this is method inside your activity
        }
    });
2
CommonSenseCode

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) {}
})}

タイマーを使用できます。テキストを入力すると、600ミリ秒待機します。 600 msの遅延を使用して、afterTextChanged()内にコードを配置します。

@Override
    public void afterTextChanged(Editable arg0) {
        // user typed: start the timer
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // do your actual work here
               editText.setText(et.getText().toString());

            }
        }, 600); // 600ms delay before the timer executes the „run“ method from TimerTask
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // nothing to do here
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // user is typing: reset already started timer (if existing)
        if (timer != null) {
            timer.cancel();
        }
    }
};

それは入力中と終了後のイベントです... textWatcherを追加し、onTextChangedメソッドにputを追加します。

if (charSequence.length() > 0){// your code }

0
alserdar

Kotlin Languageでは、このようにできます

tv_search.addTextChangedListener(mTextWatcher)

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

        override fun afterTextChanged(s: Editable?) {
            timer.cancel();
            timer = Timer()
            timer.schedule(object : TimerTask() {
                override fun run() {
                         //DO YOUR STUFF HERE
                }
            }, 1000)
        }

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

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

    }
0
Android Dev

初めてtextWatcherをスキップする場合は、次のコードを追加します。これにより、textWatcherが2回目から変更できるようになります。

    Boolean firstchange=false;
    profileEmailEditText.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) {
                    if (firstchange) {
                        emailAlertText.setVisibility(View.VISIBLE);
                    }
                    else {
                        firstchange=true;
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            });
0
priyam