70

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

私は何をすべきか?

4

17 に答える 17

167

使用する:

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 (e.g., manipulating views).
                    }
                },
                DELAY
            );
        }
    }
);

秘訣は、Timerテキストが変更されるたびにキャンセルして再スケジュールすることEditTextです。

遅延を設定する時間については、この投稿を参照してください。

于 2012-08-27T13:34:12.637 に答える
52

postDelayed() メソッドでHandlerを使用することをお勧めします。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) {
    //
 }
于 2016-02-08T11:27:02.220 に答える
11

上記の解決策はどれもうまくいきませんでした。

検索ビュー内に入力したすべての文字で 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 を開始できる入力フィールド内でテキストが変更された後に呼び出されますが、ユーザーがさらに文字を入力するとキャンセルされます (これらのコールバックが呼び出された場合の詳細については、これを参照してください)。ユーザーがそれ以上文字を入力しない場合、間隔は postDelayed に渡され、そのテキストに対して行うべき作業が呼び出されます。

このコードは、重要なユーザー入力ごとではなく、間隔ごとに 1 回だけ実行されます。

于 2017-04-08T11:20:52.347 に答える
4

彼らが書き終わったことをどのように判断しますか? edittext がフォーカスを失うことはありますか? 次にsetOnFocusChangedListenerがあります。

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

于 2012-08-27T12:36:20.527 に答える
2

また、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 the abstract method to leave the
                                           // implementation to the implementing class

}

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

// Notice I'm passing in the constructor of CustomTextWatcher
// myEditText I needed to use
myEditText.addTextChangedListener(new CustomTextWatcher(myEditText) {
    @Override
    public void textWasChanged() {
        //doSomething(); This is method inside your activity
    }
});
于 2016-01-19T14:04:35.370 に答える
-1

EditorActionListenerその目的のために使用することができます。

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            //Do something here
            return true;
        }
        return false;
    }
});
于 2012-08-27T12:36:33.150 に答える
-1

毎回新しいオブジェクトを作成するため、ケースにタイマーを使用することは最善の解決策ではありません。Timer documentationによると、ScheduledThreadPoolExecutor を使用することをお勧めします -

「タイマーは、実行のためにワンショットまたは定期的なタスクをスケジュールします。新しいコードには ScheduledThreadPoolExecutor を優先します。」

これがより良いアプローチです

Runnable runnabledelayedTask = new Runnable(){
    @Override
    public void run(){
        //TODO Perform any operation here
    }
};

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 final long DELAY = 500; // Milliseconds

        @Override
        public void afterTextChanged(final Editable s) {
            ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1);
            ScheduledFuture sf = scheduledPool.schedule(callabledelayedTask, DELAY, TimeUnit.MILLISECONDS);
            // You can cancel ScheduledFuture when needed
        }
    }
);
于 2016-02-02T08:17:27.410 に答える