studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones android filter android-edittext textwatcher textchanged

android - programacion - ¿Cómo puedo hacer algo, 0.5 segundos después de que el texto haya cambiado en mi EditText?



manual de programacion android pdf (8)

Estoy filtrando mi lista usando un EditText. Quiero filtrar la lista 0,5 segundos después de que el usuario haya terminado de escribir EditText . afterTextChanged evento TextWatcher de TextWatcher para este propósito. Pero este evento aumenta por cada cambio de personaje en EditText.

¿Que debería hacer?


¿Cómo determinas que hayan terminado de escribir? Que el texto de edición pierde el foco? Luego está setOnFocusChangedListener .

Respondiendo a la última edición en cuestión : si desea esperar un momento específico después del último trazo de tecla, debe iniciar un subproceso con la primera pulsación de tecla (utilizar TextWatcher). Registra constantemente la hora del último golpe clave. Deje que el hilo duerma hasta el momento de la última pulsación de tecla + 0,5 segundos. Si la marca de tiempo de la última pulsación de tecla no se ha actualizado, haga lo que haya intentado.


Mejor uso Handler con método postDelayed (). En la implementación de Android, Timer creará un nuevo hilo cada vez para ejecutar la tarea. Sin embargo, Handler tiene su propio Looper que se puede conectar a cualquier hilo que deseamos, por lo que no pagaremos un costo adicional para crear el hilo.

Ejemplo

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


Ninguna de las soluciones anteriores funcionó para mí.

Necesitaba una forma para que TextWatcher no activara cada carácter que ingresaba dentro de mi vista de búsqueda y mostrara algún progreso, lo que significaba que necesitaba acceder al hilo de 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) {} };

Quitar Handler en cada onTextChanged (que se invoca cuando el usuario ingresa un nuevo caracter). afterTextChanged se invoca después de que el texto ha sido cambiado dentro del campo de entrada donde podemos iniciar Runnable nuevo, pero lo cancelará si el usuario escribe más caracteres (para más información, cuando se llame a estas devoluciones de llamada, vea esto ). Si el usuario no ingresa más caracteres, el intervalo pasará en "PostDelay" y llamará al trabajo que debería hacer con ese texto.

Este código se ejecutará solo una vez por intervalo, no para cada entrada de usuario clave. Espero que ayude a alguien en el futuro.


Puede usar EditorActionListener para ese fin.

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


Puede usar RxBindings , es la mejor solución. Consulte la guía para evitar el rebote del operador de RxJava, estoy seguro de que le irá muy bien en su caso.

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


También puede usar la interfaz TextWatcher y crear su clase personalizada que la implemente para reutilizar muchas veces su CustomTextWatcher y también puede pasar vistas o lo que sea que necesite a su constructor:

public abstract class CustomTextWatcherimplements 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

}

Ahora en tu actividad puedes usarlo así:

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


Usar el temporizador para su caso no es la mejor solución porque crea un objeto nuevo cada vez. De acuerdo con la documentación de Timer ( http://developer.android.com/reference/java/util/Timer.html ) es mejor usar ScheduledThreadPoolExecutor -

"Los temporizadores programan tareas únicas o recurrentes para su ejecución. Prefieren ScheduledThreadPoolExecutor para el nuevo código".

Aquí hay un mejor enfoque

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


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

El truco está en cancelar y volver a programar el Timer cada vez, cuando el texto en EditText se cambia. ¡Buena suerte!

ACTUALIZACIÓN Para aquellos interesados ​​en cuánto tiempo establecer la demora, consulte esta publicación .