Timertask o Handler


103

Diciamo che voglio eseguire un'azione ogni 10 secondi e non è necessario aggiornare la vista.

La domanda è: è meglio (intendo più efficiente ed efficace) usare il timer con timertask come qui:

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 solo un gestore con postdelayed

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

Inoltre ti sarei grato se potessi spiegare quando utilizzare quale approccio e perché uno di essi è più efficiente di un altro (se lo è effettivamente).


2
Ho letto molti post sul comportamento irregolare di TimerTasks. Il mio consiglio sarebbe di stare alla larga da loro e di usare l'approccio gestore / postDelayed.
Sound Conception

1
Preferirei il metodo Handler-postDelay - hai più controllo e lo pianifichi dall'interno
mihail

1
Ecco un'ottima fonte per Timer vs. Handler
CodyF

TimerTask è un'attività in background, quindi non è possibile aggiornare l'interfaccia utente.
Sto

1
ha funzionato per me
..

Risposte:


96

Handlerè meglio di TimerTask.

Sia Java TimerTaskche Android Handlerti consentono di pianificare attività ripetute e ritardate su thread in background. Tuttavia, la letteratura consiglia in modo schiacciante l'uso di Handlerover TimerTaskin Android (vedi qui , qui , qui , qui , qui e qui ).

Alcuni dei problemi segnalati con TimerTask includono:

  • Impossibile aggiornare il thread dell'interfaccia utente
  • Perdite di memoria
  • Inaffidabile (non sempre funziona)
  • Le attività a lunga esecuzione possono interferire con il prossimo evento pianificato

Esempio

La migliore fonte per tutti i tipi di esempi Android che ho visto è su Codepath . Ecco un Handleresempio da lì per un'attività ripetuta.

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

Relazionato


6
@Reek No, GC dovrebbe occuparsene. Ma devi prenderti cura del eseguibile pubblicato per l'esecuzione ritardata. Nell'esempio sopra il runnable utilizzato è un'istanza di classe interna, quindi contiene un riferimento implicito alla classe contenitore (che potrebbe essere un'attività). Il runnable rimarrà nella coda dei messaggi del looper associato al gestore fino alla successiva ora di esecuzione, che potrebbe essere dopo che il contesto non è valido e potrebbe perdere l'istanza della classe contenitore. È possibile cancellare tali riferimenti utilizzando mHandler.removeCallbacks(runnableCode)al momento opportuno (ad esempio onStop()per un'attività).
bitbybit

7
Il modo migliore di presentare referenze in assoluto !!! (vedi qui, qui, qui, qui, qui e qui).
iRavi iVooda

e se volessi usarlo all'interno di un ViewModel? non è contro l'ideale di non avere cose Android lì?
desgraci

@desgraci, non ho usato un ViewModel, ma dalla documentazione vedo solo che dice che ViewModel non dovrebbe accedere alla gerarchia della vista o contenere un riferimento all'attività o al frammento. Non vedo nulla che vieti di avere "cose ​​Android" in generale.
Suragch

Ad oggi questi riferimenti sono per me obsoleti e non sufficientemente informativi per essere presi in considerazione. Questi 4 inconvenienti elencati sono reali solo se si programma male il codice. I TimerTasks sono ancora un'ottima scelta se si desidera eseguire periodicamente qualcosa in background e alla fine eseguire qualcosa su UIThread se si applicano alcune condizioni.
David

18

Ci sono alcuni svantaggi nell'utilizzo di Timer

Crea un solo thread singolo per eseguire le attività e se un'attività impiega troppo tempo per essere eseguita, altre attività ne risentono. Non gestisce le eccezioni generate dalle attività e il thread termina semplicemente, il che influisce su altre attività pianificate e non vengono mai eseguite

Copiato da:

TimerTask vs Thread.sleep vs Handler postDelayed - più preciso per chiamare la funzione ogni N millisecondi?


6
quindi che ne dici di un'attività one-shot? sembra che forse Timer è meglio per quello perché non hai il sovraccarico della coda dei messaggi?
Michael

2
Immagino che non lo sapremo mai
Denny

6

Versione di Kotlin della risposta accettata:

val handler = Handler()

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

handler.post(runnableCode)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.