Cédric Creusot

Artisan Logiciel sur Mobile

Utilisation de Timer avec Flutter

Durant le confinement, je souhaitais créer une application de pomodoro toute simple. J’ai donc choisi d’utiliser Flutter pour ça. Étant donné la facilité de faire des prototypes avec Flutter, je me suis dit que ce serait l’occasion de pratiquer.

Qui dit Pomodoro, dit Timer

Avantage de Flutter, c’est Dart, il a une panoplie d’outils bien utiles pour la réalisation d’application. J’ai donc découvert la classe Timer.

La documentation est très légère et ne nous indique pas ce qui se passe sous le capot :

A count-down timer that can be configured to fire once or repeatedly.

The timer counts down from the specified duration to 0. When the timer reaches 0, the timer invokes the specified callback function. Use a periodic timer to repeatedly count down the same interval.

Je me suis principalement servie de Timer.periodic(...) qui permet comme son nom l’indique de créer un timer qui va se répéter tout les X temps. Très pratique pour une application comme la mienne.

Il s’avère que quand nous lançons un Timer, celui-ci continue de s’exécuter même lorsque notre application se retrouve en background.

Or, c’est à ce moment-là que je me suis posé la question : Que ce passe-t-il pour que notre Timer continuer son exécution malgré que le thread d’affichage de notre application soit en pause ?

Voici le code source de Timer.periodic(...)

factory Timer.periodic(Duration duration, void callback(Timer timer)) {
    if (Zone.current == Zone.root) {
      // No need to bind the callback. We know that the root's timer will
      // be invoked in the root zone.
      return Zone.current.createPeriodicTimer(duration, callback);
    }
    var boundCallback = Zone.current.bindUnaryCallbackGuarded<Timer>(callback);
    return Zone.current.createPeriodicTimer(duration, boundCallback);
  }

Ok ! Bon ça ne nous dit pas pourquoi cela fonctionne alors que le thread principal est en background ?! Pour cela, il faut comprendre le concept de Zone au sein de Dart.

Qu’est-ce qu’une Zone dans Dart

Une zone dans Dart permet l’exécution d’un code de façon asynchrone dans le scope du processus qui la lancé. Pour résumer avec le cas du Timer, quand nous lançons un Timer.periodic(...) nous exécutons en fait de manière répétitive la callback qui se comporte comme un Future.

Or, tout ce qui concerne l’asynchronisme dans Dart est exécuté dans le processus principal, a l’exception des Isolate qui lance un tout nouveau processus.

Je vous invite à consulter cette article pour comprendre le mécanisme

Quelle implication aurait Timer sur mon application

Malheureusement, pour une bonne application de pomodoro, il faut que celle-ci puisse nous notifier que le temps s’écoule et nous prévenir quand celui-ci a fini.

Or Timer étant exécuté sur le processus principal, et que la VM Dart tourne avec celui de notre application. Si, en tout cas sur Android, nous sortons de l’application sans la détruire. Le Timer continuera à s’exécuter jusqu’à un certain point. Ce point, c’est le système qui le définit. Sur mon téléphone personnel, il a pris 30min avant d’arrêter l’exécution de mon application. Si je décidais d’activer l’option permettant de détruire les activités en background, ce temps est quasi instantané.

Est-ce une bonne solution d’utiliser Timer ? Non dans le cas où avoir une exécution continue, même après mise en background est nécessaire.

Dans mon cas d’application, j’ai donc choisi de laisser de côté Timer, pour implémenter un Service Android, pour avoir le comportement souhaité.

Dans quel cas Timer peut-être utile

Eh bien, Timer peut-être utile quand vous souhaitez par exemple faire une animation qui se répète, ou que vous souhaitez fetch une donner tous les X temps quand votre application est au premier plan, ou encore d’exécuter une fonctionnalité pour montré une évolution/notification sur votre interface, etc.

À vous de décider.