Timertask o Handler

103

Digamos que quiero realizar alguna acción cada 10 segundos y no es necesario que actualice la vista.

La pregunta es: ¿es mejor (quiero decir más eficiente y efectivo) usar el temporizador con timertask como aquí?

final Handler handler = new Handler();

TimerTask timertask = new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            public void run() {
               <some task>
            }
        });
    }
};
timer = new Timer();
timer.schedule(timertask, 0, 15000);
}

o simplemente un controlador con posretrasado

final Handler handler = new Handler(); 
final Runnable r = new Runnable()
{
    public void run() 
    {
        <some task>
    }
};
handler.postDelayed(r, 15000);

También le agradecería que me explicara cuándo usar qué enfoque y por qué uno de ellos es más eficiente que otro (si es que realmente lo es).

keyersoze
fuente
2
He leído muchas publicaciones sobre el comportamiento irregular de TimerTasks. Mi consejo sería mantenerse alejado de ellos y utilizar el enfoque handler / postDelayed.
Sound Conception
1
Preferiría el método Handler-postDelay: tiene más control y lo programa desde adentro
mihail
1
Aquí hay una gran fuente para Timer vs. Handler
CodyF
TimerTask es una tarea en segundo plano, por lo que no puede actualizar la interfaz de usuario. Solo digo ...
Yousha Aleayoub
1
trabajado para me..thanks
jyotsna

Respuestas:

96

Handleres mejor que TimerTask.

Tanto Java TimerTaskcomo Android le Handlerpermiten programar tareas retrasadas y repetidas en subprocesos en segundo plano. Sin embargo, la literatura recomienda abrumadoramente usar Handlerover TimerTasken Android (ver aquí , aquí , aquí , aquí , aquí y aquí ).

Algunos de los problemas reportados con TimerTask incluyen:

  • No se puede actualizar el hilo de la interfaz de usuario
  • Pérdidas de memoria
  • No confiable (no siempre funciona)
  • Las tareas de larga duración pueden interferir con el próximo evento programado

Ejemplo

La mejor fuente para todo tipo de ejemplos de Android que he visto está en Codepath . A continuación se Handlermuestra un ejemplo de una tarea repetida.

// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
      // Do something here on the main thread
      Log.d("Handlers", "Called on main thread");
      // Repeat this the same runnable code block again another 2 seconds
      handler.postDelayed(runnableCode, 2000);
    }
};
// Start the initial runnable task by posting through the handler
handler.post(runnableCode);

Relacionado

Suragch
fuente
6
@Reek No, GC debería encargarse de eso. Pero debe encargarse del ejecutable publicado para ejecución retrasada. En el ejemplo anterior, el ejecutable utilizado es una instancia de clase interna, por lo que contiene una referencia implícita a la clase que lo contiene (que podría ser una actividad). El ejecutable permanecerá en la cola de mensajes del looper asociado del manejador hasta su próxima ejecución, que puede ser después de que el contexto no sea válido y podría filtrar la instancia de la clase que lo contiene. Puede borrar dichas referencias utilizándolas mHandler.removeCallbacks(runnableCode)en el momento adecuado (por ejemplo, onStop()para una actividad).
bitbybit
7
¡La mejor manera de presentar referencias! (ver aquí, aquí, aquí, aquí, aquí y aquí).
iRavi iVooda
y ¿qué pasa si quiero usar eso dentro de un ViewModel? ¿No está en contra del ideal de no tener cosas de Android ahí?
desgraci
@desgraci, no he usado un ViewModel, pero en la documentación solo veo que dice que ViewModel no debería acceder a la jerarquía de vistas o contener una referencia a la Actividad o Fragmento. No veo nada que prohíba tener "cosas de Android" en general.
Suragch
Hasta el día de hoy, esas referencias están desactualizadas para mí y no son lo suficientemente informativas como para ser tomadas en consideración. Esos 4 inconvenientes enumerados solo son reales si programa mal su código. TimerTasks sigue siendo una muy buena opción si desea ejecutar periódicamente algo en segundo plano y, finalmente, ejecutar algo en UIThread si se aplica alguna condición.
David
18

Hay algunas desventajas de usar Timer

Crea un solo hilo para ejecutar las tareas y si una tarea tarda demasiado en ejecutarse, otras tareas se ven afectadas. No maneja excepciones lanzadas por tareas y el hilo simplemente termina, lo que afecta otras tareas programadas y nunca se ejecutan

Copiado de:

TimerTask vs Thread.sleep vs Handler postDelayed: ¿la función más precisa para llamar cada N milisegundos?

Praveena
fuente
6
Entonces, ¿qué pasa con una tarea de una sola vez? ¿Parece que Timer es mejor para eso porque no tienes la sobrecarga de la cola de mensajes?
Michael
2
Supongo que nunca lo sabremos
Denny
6

Versión de Kotlin de la respuesta aceptada:

val handler = Handler()

val runnableCode = object : Runnable {
    override fun run() {
       Log.d("Handlers", "Called on main thread")
       handler.postDelayed(this, 2000)
    }
}

handler.post(runnableCode)
sma6871
fuente