asynctask - timer schedule java
¿Pausar/detener y comenzar/reanudar Java TimerTask continuamente? (7)
Android no reutilizará una TimerTask que ya ha sido programada una vez. Por lo tanto, es necesario volver a establecer el Timer y el TimerTask, por ejemplo como este en un Fragmento:
private Timer timer;
private TimerTask timerTask;
public void onResume ()
{
super.onResume();
timer = new Timer();
timerTask = new MyTimerTask();
timer.schedule(timerTask, 0, 1000);
}
public void onPause ()
{
super.onPause();
timer.cancel(); // Renders Timer unusable for further schedule() calls.
}
Tengo una pregunta simple con respecto a Java TimerTask. ¿Cómo puedo pausar / reanudar dos tareas TimerTask basadas en una condición determinada? Por ejemplo, tengo dos temporizadores que se ejecutan entre sí. Cuando se cumple una determinada condición dentro de la tarea del primer temporizador, el primer temporizador se detiene e inicia el segundo temporizador, y sucede lo mismo cuando se cumple una determinada condición dentro de la tarea del segundo temporizador. La siguiente clase muestra exactamente lo que quiero decir:
public class TimerTest {
Timer timer1;
Timer timer2;
volatile boolean a = false;
public TimerTest() {
timer1 = new Timer();
timer2 = new Timer();
}
public void runStart() {
timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
}
class Task1 extends TimerTask {
public void run() {
System.out.println("Checking a");
a = SomeClass.getSomeStaticValue();
if (a) {
// Pause/stop timer1, start/resume timer2 for 5 seconds
timer2.schedule(new Task2(), 5000);
}
}
}
class Task2 extends TimerTask{
public void run() {
System.out.println("Checking a");
a = SomeClass.getSomeStaticValue();
if (!a) {
// Pause/stop timer2, back to timer1
timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
}
// Do something...
}
}
public static void main(String args[]) {
TimerTest tt = new TimerTest();
tt.runStart();
}
}
Entonces, mi pregunta es, ¿cómo hago una pausa en el timer1
mientras timer2
el timer2
y viceversa mientras el timer2
está funcionando? El rendimiento y el tiempo son mi principal preocupación ya que esto debe implementarse dentro de otro hilo en ejecución. Por cierto, estoy tratando de implementar estos temporizadores concurrentes en Android.
¡Gracias por tu ayuda!
Desde TimerTask.cancel()
:
Tenga en cuenta que llamar a este método desde el método de ejecución de una tarea de temporizador de repetición garantiza absolutamente que la tarea de temporizador no se ejecutará de nuevo.
Así que una vez cancelado, no volverá a correr. Estaría mejor en lugar de usar el ScheduledExecutorService
más moderno (de Java 5+).
Edición: La construcción básica es:
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(runnable, 0, 1000, TimeUnit.MILLISECONDS);
pero al examinarlo no hay forma de cancelar esa tarea una vez que haya comenzado sin cerrar el servicio, lo cual es un poco extraño.
TimerTask
puede ser más fácil en este caso, pero deberá crear una nueva instancia cuando inicie una. No puede ser reutilizado.
Alternativamente, podría encapsular cada tarea como un servicio transitorio separado:
final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
Runnable task1 = new Runnable() {
public void run() {
a++;
if (a == 3) {
exec.shutdown();
exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(task2, 0, 1000, TimeUnit.MILLISECONDS)
}
}
};
exec.scheduleAtFixedRate(task1, 0, 1000, TimeUnit.MILLISECONDS);
En mi opinión, esto es un tanto equivocado. Si su código necesita garantías de tiempo, no puede usar el temporizador de todos modos, ni lo desearía. "Esta clase no ofrece garantías en tiempo real: programa las tareas usando el método Object.wait (long)".
La respuesta, en mi humilde opinión, es que no desea pausar y reiniciar sus temporizadores. Solo desea evitar que sus métodos de ejecución hagan su negocio. Y eso es fácil: simplemente envuélvelos en una declaración if
. El interruptor está encendido, se ejecutan, el interruptor está apagado, pierden ese ciclo.
Edit: La pregunta ha cambiado sustancialmente de lo que era originalmente, pero dejaré esta respuesta en caso de que ayude a alguien. Mi punto es: si no te importa cuándo se dispara tu evento en el lapso de milisegundos de N (solo que no EXCEDE una vez cada milisegundos de N), puedes usar condicionales en los métodos de ejecución. Este es, de hecho, un caso muy común, especialmente cuando N es inferior a 1 segundo.
La solución más fácil que encontré: simplemente agregue un valor booleano en el código de ejecución en la tarea del temporizador, así:
timer.schedule( new TimerTask() {
public void run() {
if(!paused){
//do your thing
}
}
}, 0, 1000 );
Revisando su código fuente, aquí están los cambios (que casi validan mi respuesta anterior)
En la tarea 1:
// Stop timer1 and start timer2
timer1.cancel();
timer2 = new Timer(); // <-- just insert this line
timer2.scheduleAtFixedRate(new Task2(), 0, 1000);
y en task2:
// Stop timer2 and start timer1
timer2.cancel();
timer1 = new Timer(); // <-- just insert this other
timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
Se ejecuta en mi máquina:
¡funciona! http://img687.imageshack.us/img687/9954/capturadepantalla201001m.png
Si ya ha cancelado un temporizador, no puede reiniciarlo, tendrá que crear uno nuevo.
Ver esta answer , contiene un video y el código fuente de cómo hice algo similar.
Básicamente hay dos métodos: pause
y resume
En pausa:
public void pause() {
this.timer.cancel();
}
En resumen:
public void resume() {
this.timer = new Timer();
this.timer.schedule( aTask, 0, 1000 );
}
Eso hace que la percepción de pausa / reanudar.
Si sus temporizadores realizan acciones diferentes en función del estado de la aplicación, puede considerar usar el StatePattern
El puño define un estado abstracto:
abstract class TaskState {
public void run();
public TaskState next();
}
Y proporciona tantos estados como quieras. La clave es que un estado te lleva a otro.
class InitialState extends TaskState {
public void run() {
System.out.println( "starting...");
}
public TaskState next() {
return new FinalState();
}
}
class FinalState extends TaskState {
public void run() {
System.out.println("Finishing...");
}
public TaskState next(){
return new InitialState();
}
}
Y luego cambia el estado en su temporizador.
Timer timer = new Timer();
TaskState state = new InitialState();
timer.schedule( new TimerTask() {
public void run() {
this.state.run();
if( shouldChangeState() ) {
this.state = this.state.next();
}
}
}, 0, 1000 );
Finalmente, si lo que necesita es realizar lo mismo, pero a diferentes velocidades, puede considerar usar el TimingFramework . Es un poco más complejo, pero le permite hacer animaciones geniales, al permitir que la pintura de ciertos componentes se realice a diferentes velocidades (en lugar de ser lineal)
Soy capaz de detener un temporizador y una tarea usando el siguiente código:
if(null != timer)
{
timer.cancel();
Log.i(LOG_TAG,"Number of cancelled tasks purged: " + timer.purge());
timer = null;
}
if(task != null)
{
Log.i(LOG_TAG,"Tracking cancellation status: " + task.cancel());
task = null;
}