Tâche horaire ou gestionnaire

104

Disons que je veux effectuer une action toutes les 10 secondes et qu'il n'est pas nécessairement nécessaire de mettre à jour la vue.

La question est: vaut-il mieux (je veux dire plus efficace et plus efficace) d'utiliser une minuterie avec une tâche de temps comme ici:

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

ou juste un gestionnaire avec postdelayed

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

Je vous serais également reconnaissant de bien vouloir expliquer quand utiliser quelle approche et pourquoi l'une d'elles est plus efficace qu'une autre (si elle l'est réellement).

claviers
la source
2
J'ai lu de nombreux articles sur le comportement irrégulier des TimerTasks. Mon conseil serait de les éviter et d'utiliser l'approche handler / postDelayed.
Sound Conception
1
Je préfère la méthode Handler-postDelay - vous avez plus de contrôle et vous le programmez de l'intérieur
mihail
1
Voici une excellente source pour Timer vs Handler
CodyF
TimerTask est une tâche d'arrière-plan, vous ne pouvez donc pas mettre à jour l'interface utilisateur. Juste en disant ...
Yousha Aleayoub
1
travaillé pour moi
jyotsna

Réponses:

97

Handlerest mieux que TimerTask.

Java TimerTasket Android Handlervous permettent tous deux de planifier des tâches différées et répétées sur les threads d'arrière-plan. Cependant, la littérature recommande massivement d'utiliser Handlerover TimerTaskdans Android (voir ici , ici , ici , ici , ici et ici ).

Certains des problèmes signalés avec TimerTask incluent:

  • Impossible de mettre à jour le fil de discussion de l'interface utilisateur
  • Fuites de mémoire
  • Peu fiable (ne fonctionne pas toujours)
  • Les tâches de longue durée peuvent interférer avec le prochain événement planifié

Exemple

La meilleure source pour toutes sortes d'exemples Android que j'ai vus est sur Codepath . Voici un Handlerexemple à partir de là pour une tâche répétitive.

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

en relation

Suragch
la source
6
@Reek Non, GC devrait s'en occuper. Mais vous devez vous occuper de l'exécutable posté pour une exécution retardée. Dans l'exemple ci-dessus, l'exécutable utilisé est une instance de classe interne, donc contient une référence implicite à la classe contenant (qui peut être une activité). L'exécutable restera dans la file d'attente de messages du boucleur associé au gestionnaire jusqu'à sa prochaine exécution, qui peut être après que le contexte est invalide et pourrait laisser échapper l'instance de classe contenante. Vous pouvez effacer ces références en utilisant mHandler.removeCallbacks(runnableCode)au moment opportun (par exemple onStop()pour une activité).
bitbybit
7
La meilleure façon de présenter des références jamais !!! (voir ici, ici, ici, ici, ici et ici).
iRavi iVooda
et que faire si je veux utiliser cela dans un ViewModel? n'est pas contre l'idéal de ne pas avoir de choses Android là-bas?
desgraci
@desgraci, je n'ai pas utilisé de ViewModel, mais d'après la documentation, je vois seulement que le ViewModel ne doit pas accéder à la hiérarchie des vues ou contenir une référence à l'activité ou au fragment. Je ne vois rien d'interdit d'avoir des "choses Android" en général.
Suragch
À ce jour, ces références me sont dépassées et ne sont pas suffisamment informatives pour être prises en considération. Ces 4 inconvénients énumérés ne sont réels que si vous programmez mal votre code. Les TimerTasks sont toujours un très bon choix si vous souhaitez exécuter périodiquement quelque chose en arrière-plan et éventuellement exécuter quelque chose sur l'UIThread si une condition s'applique.
David
18

Il y a quelques inconvénients à utiliser Timer

Il ne crée qu'un seul thread pour exécuter les tâches et si une tâche prend trop de temps à s'exécuter, d'autres tâches en souffrent. Il ne gère pas les exceptions levées par les tâches et le thread se termine simplement, ce qui affecte les autres tâches planifiées et elles ne sont jamais exécutées

Copié depuis:

TimerTask vs Thread.sleep vs Handler postDelayed - la fonction la plus précise pour appeler toutes les N millisecondes?

Praveena
la source
6
alors qu'en est-il pour une tâche ponctuelle? il semble que peut-être Timer est meilleur pour cela parce que vous n'avez pas la surcharge de la file d'attente des messages?
Michael
2
Je suppose que nous ne saurons jamais
Denny
6

Version Kotlin de la réponse acceptée:

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
la source