14. Asynchronisme 1/2

Dimanche 14/1/24
524 Mots
3 Minutes

1. Asynchronisme : la théorie

Asynchronisme

L'asynchronisme permet d'exécuter des opérations de manière non bloquante, ce qui garantit que l'application ne fige pas lorsqu'elle attend la fin d'une tâche longue, comme une requête réseau ou l'accès à un fichier.

Dans le contexte de Flutter, l'asynchronisme est crucial pour optimiser les performances de l'application. En permettant à l'interface utilisateur de rester fluide et réactive pendant que des tâches complexes se déroulent en arrière-plan, on améliore considérablement l'expérience utilisateur. Cela évite les blocages lorsque l'application attend des données ou traite des opérations longues, comme la communication avec une API.

L'asynchronisme peut être implémenté dans un projet Flutter à l'aide de plusieurs outils, tels que les Future et les Stream.

Future

Un Future représente une opération qui s'exécutera dans le futur, pouvant renvoyer une valeur ou une erreur à sa résolution. En Flutter, les Future sont souvent utilisés pour les tâches qui ne bloquent pas l'interface utilisateur, comme les requêtes HTTP.

Pour déclarer une fonction asynchrone en Dart, on utilise le mot-clé async, et pour attendre la résolution d'un Future, on utilise le mot-clé await. Cela permet de suspendre temporairement l'exécution de la fonction jusqu'à ce que le Future soit complété.

Exemple :

dart
Future<List<Data>> loadData() async {
  final response = await http.get('https://example.com/hello');
  if (response.statusCode == 200) {
    return dataFromJson(response.body);
  } else {
    throw Exception('Failed to load data');
  }
}

Exécution de plusieurs tâches asynchrones en parallèle

Pour exécuter plusieurs tâches en parallèle et attendre leur complétion, Flutter propose des méthodes comme Future.wait. Cela est utile lorsque les tâches sont indépendantes les unes des autres. Voici comment cela fonctionne :

dart
Future<void> performTasks() async {
  await Future.wait([
    task1(),
    task2(),
    task3(),
  ]);
}

Dans cet exemple, les tâches task1, task2, et task3 seront exécutées en parallèle et la fonction performTasks attendra que toutes soient terminées avant de continuer.

Une autre méthode utile est Future.whenComplete, qui permet d'exécuter une action une fois qu'un Future est complété, qu'il ait réussi ou échoué :

dart
Future<void> performTask() {
  return task().whenComplete(() {
    print('Task completed');
  });
}

Stream

Un Stream est un flux de données qui peut émettre plusieurs valeurs au fil du temps. Contrairement à un Future qui ne renvoie qu'une seule valeur ou erreur, un Stream peut émettre plusieurs événements successifs. Cela le rend idéal pour des cas d'utilisation comme les notifications push, les mises à jour en temps réel, ou le suivi de données dynamiques.

En Flutter, les Stream sont souvent combinés avec le widget StreamBuilder, qui permet de construire dynamiquement l'interface utilisateur en fonction des données reçues via un Stream.

Exemple d'implémentation d'un Stream qui émet la position de l'utilisateur toutes les secondes :

dart
Stream<UserPosition> getUserLocationStream() {
  return Stream.periodic(Duration(seconds: 1), (count) {
    return UserPosition(45.521563, -122.677433);
  });
}

Pour afficher cette position sur une carte et mettre à jour l'interface utilisateur en temps réel, vous pouvez utiliser un StreamBuilder :

dart
StreamBuilder<UserPosition>(
  stream: getUserLocationStream(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return Text('Position: ${snapshot.data!.latitude}, ${snapshot.data!.longitude}');
    } else {
      return CircularProgressIndicator();
    }
  },
)

Ce widget réagira automatiquement aux nouveaux événements du Stream et mettra à jour l'interface en conséquence.

Conclusion

L'asynchronisme est un concept fondamental pour améliorer les performances et la réactivité des applications Flutter. Les Future et Stream sont des outils puissants qui permettent de gérer des opérations longues ou répétitives de manière efficace, sans bloquer l'interface utilisateur.