package com.jdroid.android.listener; import android.text.Editable; import android.text.TextWatcher; import com.jdroid.android.application.AbstractApplication; import com.jdroid.java.concurrent.ExecutorUtils; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public abstract class RemoteSearchTextWatcher implements TextWatcher { // The search frequency in milliseconds private static final int SEARCH_FREQUENCY = 1000; private TimerSearchRunnable timerSearchRunnable; private Thread timerSearchThread; public RemoteSearchTextWatcher() { startWatching(); } public void startWatching() { timerSearchRunnable = new TimerSearchRunnable(); timerSearchThread = new Thread(timerSearchRunnable); timerSearchThread.start(); } public void stopWatching() { timerSearchThread.interrupt(); } /** * @see android.text.TextWatcher#afterTextChanged(android.text.Editable) */ @Override public void afterTextChanged(Editable s) { try { timerSearchRunnable.queue.put(s.toString()); } catch (InterruptedException e) { AbstractApplication.get().getExceptionHandler().logHandledException(e); } } /** * @see android.text.TextWatcher#beforeTextChanged(java.lang.CharSequence, int, int, int) */ @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Nothing here by default. } /** * @see android.text.TextWatcher#onTextChanged(java.lang.CharSequence, int, int, int) */ @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Nothing here by default. } protected abstract void onPerformSearch(String searchValue); private class TimerSearchRunnable implements Runnable { private BlockingQueue<String> queue = new ArrayBlockingQueue<>(20); @Override public void run() { Boolean exit = false; while (!exit) { try { String searchValue = queue.take(); if (queue.isEmpty()) { ExecutorUtils.sleepInMillis(SEARCH_FREQUENCY); // If after waiting for a SEARCH_FREQUENCY, no more input was added, the search is performed. if (queue.isEmpty()) { RemoteSearchTextWatcher.this.onPerformSearch(searchValue); } } } catch (InterruptedException e) { exit = true; } } } } }