android - ejemplo - runnable thread
removeCallbacks no detiene el ejecutable (4)
Aquí hay otra forma de lograr lo que mtmurdock está describiendo. Esta clase permitirá la edición de variables de instancia en cualquier clase que Runnable se defina como una clase interna anónima.
package support;
/**
* Runnable that can be stopped from executing
* @author JTRONLABS
*/
public abstract class KillableRunnable implements Runnable{
private boolean isKilled=false;
/**
* Instead of Overriding run(), override this method to perform a Runnable operation.
* This will allow editing instance variables in the class that this Runnable is defined
*/
public abstract void doWork();
//The handler that posts this Runnable will call this method.
//By default, check if it has been killed. doWork() will now be the method
//override to implement this Runnable
@Override
final public void run(){
if(!isKilled){
doWork();
}
}
final public void kill(){
isKilled=true;
}
}
Estoy llamando desde un método:
myHandler.postDelayed(mMyRunnableHide, 6000);
que llama:
public Runnable mMyRunnableHide = new Runnable()
{
public void run()
{
mTextDisplay.setText("");
DisplayX();
}
};
si se hace clic en un botón en la pantalla, quiero detener el ejecutable:
Button next = (Button) findViewById(R.id.Breaction);
next.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
myHandler.removeCallbacks(mMyRunnableHide);
mTextDisplay.setText("");
DisplayX();
}
});
}
los removecallbacks no detienen el ejecutable. ¿Qué estoy haciendo mal? ¿Estoy usando el método correcto? Solo quiero que el ejecutable "No se ejecute" cuando el usuario hace clic en el botón.
Gracias por cualquier ayuda.
Me parece que removeCallbacks(..)
solo detiene los mensajes pendientes (Runnables). Si su ejecutable ya ha comenzado, entonces no hay forma de detenerlo (al menos no de esta manera).
Alternativamente, puede extender la clase Runnable y darle algún tipo de interruptor de matar como este:
public class MyRunnable implements Runnable
{
private boolean killMe = false;
private void run()
{
if(killMe)
return;
/* do your work */
}
private void killRunnable()
{
killMe = true;
}
}
Esto solo evitará que se inicie, pero de vez en cuando podría verificar killMe
y rescatar. Si está bucleando el ejecutable (como algún tipo de hilo de fondo) puede decir:
while(!killMe) {
/* do work */
}
Espero que esto ayude
EDITAR Solo quería publicar una actualización sobre esto. Desde esta publicación original, Google ha creado una gran clase llamada AsyncTask que maneja todo esto para usted. Cualquiera que lea esto realmente debería investigarlo porque es la forma correcta de hacer las cosas.
Puedes leer sobre esto here
No creo que removeCallbacks (..) solo detenga los mensajes pendientes (Runnables), creo que removeCallbacks (..) no funciona tiene otra causa, pero no sé. porque postDelayed (..) y removeCallbacks (..) están en el mismo hilo
Handler.removeCallback
es sincrónico y funcionará muy bien siempre que:
-
postDelayed
apostDelayed
siempre en el hilo principal. -
removeCallback
siempre en el hilo principal - No vuelve a llamar a
postDelayed
después de haber eliminado las devoluciones de llamada.
Entonces, en su caso removeCallbacks
se llama desde un manejador de botones, que se ejecuta en el hilo principal. Pero no mostró en su código el punto desde el que llama postDelayed
. Si lo llamas desde un hilo de fondo, ahí es donde está tu problema.
Si está seguro de que no llama a ninguno de estos métodos desde los subprocesos de fondo, y el orden de las llamadas es correcto, entonces puede dejar las tareas no canceladas sin vida debido a la recreación de actividad en los cambios de configuración (rotación de pantalla, etc.). Siempre asegúrese de llamar a removeCallbacks
nuevamente en el método onDestroy
para evitar este tipo de problemas.