Stream Controllers
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 78 sur 110.
Alors que les générateurs async* sont excellents pour créer des flux avec des données prédéfinies, vous avez parfois besoin de plus de contrôle - comme ajouter des données à un flux à partir de différentes parties de votre code. C'est là que StreamController intervient.
Un StreamController agit comme un gestionnaire pour un stream. Il vous donne un « sink » pour ajouter des données et un « stream » auquel les écouteurs peuvent s'abonner :
import 'dart:async';
void main() {
var controller = StreamController<String>();
// Écouter le flux
controller.stream.listen((data) {
print('Received: $data');
});
// Ajouter des données via le sink
controller.add('Hello');
controller.add('World');
controller.close(); // Toujours fermer une fois terminé
}La méthode add() ajoute de nouvelles valeurs dans le flux, et tous les écouteurs les reçoivent immédiatement. Vous devriez toujours appeler close() lorsque vous avez terminé pour libérer les ressources.
Par défaut, un stream ne peut avoir qu'un seul écouteur. Pour plusieurs écouteurs, utilisez un contrôleur de diffusion (broadcast controller) :
import 'dart:async';
void main() {
var controller = StreamController<int>.broadcast();
controller.stream.listen((n) => print('Listener 1: $n'));
controller.stream.listen((n) => print('Listener 2: $n'));
controller.add(42);
controller.close();
}Les StreamControllers sont essentiels en POO pour construire des classes pilotées par les événements - comme notifier plusieurs parties de votre application lorsque les données changent, gérer les actions de l'utilisateur ou gérer les mises à jour en temps réel au sein de vos objets.
Défi
FacileConstruisons un système de concentrateur de messages qui permet à plusieurs abonnés de recevoir des messages en temps réel ! Vous utiliserez un StreamController pour gérer le flux de messages et démontrer comment les flux de diffusion (broadcast streams) permettent d'avoir plusieurs écouteurs.
Vous organiserez votre code en deux fichiers :
message_hub.dart: Créez une classeMessageHubqui gère la distribution des messages à l'aide d'un StreamController. Votre concentrateur doit :- Utiliser un
StreamController<String>de type broadcast en interne afin que plusieurs écouteurs puissent s'abonner - Fournir un getter nommé
messagesqui renvoie le flux pour que les écouteurs puissent s'y abonner - Avoir une méthode
broadcast(String message)qui ajoute un message au flux - Avoir une méthode
shutdown()qui ferme le contrôleur
- Utiliser un
main.dart: Importez votre concentrateur de messages et mettez en place un scénario avec plusieurs abonnés écoutant le même flux :- Créez une instance de
MessageHub - Ajoutez un premier écouteur qui affiche les messages au format :
Subscriber A: [message] - Ajoutez un second écouteur qui affiche les messages au format :
Subscriber B: [message] - Diffusez trois messages :
Hello everyone,Welcome to the hub, etGoodbye - Fermez le concentrateur
- Créez une instance de
N'oubliez pas d'importer dart:async dans votre fichier de concentrateur de messages pour accéder à StreamController. Remarquez comment les deux abonnés reçoivent chaque message diffusé - c'est toute la puissance des flux de diffusion !
Sortie attendue :
Subscriber A: Hello everyone
Subscriber B: Hello everyone
Subscriber A: Welcome to the hub
Subscriber B: Welcome to the hub
Subscriber A: Goodbye
Subscriber B: GoodbyeAide-mémoire
Un StreamController gère un flux (stream), offrant un contrôle sur le moment et la manière dont les données sont ajoutées. Il vous fournit un « sink » (puits) pour ajouter des données et un « stream » auquel les auditeurs peuvent s'abonner.
Utilisation basique :
import 'dart:async';
var controller = StreamController<String>();
// Listen to the stream
controller.stream.listen((data) {
print('Received: $data');
});
// Add data through the sink
controller.add('Hello');
controller.add('World');
controller.close(); // Always close when done
La méthode add() pousse de nouvelles valeurs dans le flux. Les auditeurs les reçoivent immédiatement. Appelez toujours close() lorsque vous avez terminé pour libérer les ressources.
Par défaut, un flux ne peut avoir qu'un seul auditeur. Pour plusieurs auditeurs, utilisez un contrôleur de diffusion (broadcast) :
var controller = StreamController<int>.broadcast();
controller.stream.listen((n) => print('Listener 1: $n'));
controller.stream.listen((n) => print('Listener 2: $n'));
controller.add(42);
controller.close();
Les StreamControllers sont essentiels pour créer des classes pilotées par les événements, notifier plusieurs parties de votre application lorsque les données changent, gérer les actions des utilisateurs ou gérer les mises à jour en temps réel.
Essayez vous-même
import 'message_hub.dart';
void main() {
// TODO: Créer une instance de MessageHub
// TODO: Ajouter un premier écouteur qui affiche : Subscriber A: [message]
// TODO: Ajouter un deuxième écouteur qui affiche : Subscriber B: [message]
// TODO: Diffuser trois messages :
// - "Hello everyone"
// - "Welcome to the hub"
// - "Goodbye"
// TODO: Fermer le hub
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesBibliothèques et importsIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesVariables d'instanceBases des constructeursRécapitulatif - Calculatrice simple4Null Safety
Introduction à la Null SafetyNullable vs Non-NullableLes opérateurs ? et !Le mot-clé late et la Null SafetyLes opérateurs Null-AwareLa Null Safety dans les classesRécapitulatif - Système de profil utilisateur7Classes abstraites et Interfaces
Classes abstraitesMéthodes abstraitesInterfaces en DartInterfaces implicitesImplémentation vs ExtensionInterfaces multiplesRécapitulatif - Calculateur de formes10Collections et Génériques
Aperçu des List, Set et MapCollections Type-SafeClasses génériquesMéthodes génériquesContraintes de généricitéIterable & IteratorRécapitulatif - Stockage générique2Les constructeurs en Dart
Constructeur par défautConstructeurs nommésListes d'initialisationConstructeurs constantsConstructeurs factoryConstructeurs de redirectionRécapitulatif - Shape Builder5Encapsulation
Membres publics vs privésLa convention du préfixe _Visibilité au niveau de la bibliothèqueApprofondissement des Getters & SettersMasquage d'informationsRécapitulatif - Dossiers d'étudiants8Mixins
Introduction aux MixinsCréation de MixinsUtilisation de plusieurs MixinsLe mot-clé on dans les MixinsMixin vs HéritageMixin vs InterfaceRécapitulatif - Système Animal11Méthodes spéciales
Redéfinition de toString()Redéfinition de hashCode & ==Interface ComparableMéthode call()Redéfinition de noSuchMethodRécapitulatif - Collection personnalisée14Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie3Propriétés de classe
Membres d'instance vs statiquesChamps Final & ConstVariables LateMéthodes et champs statiquesGetters et SettersRécapitulatif - Gestionnaire de compte bancaire6Héritage
Bases de l'héritageLe mot-clé superRedéfinition de méthodeL'annotation @overrideLe mot-clé final pour les classesConstructeurs et héritageRécapitulatif - Hiérarchie des employés9Polymorphisme
Bases du polymorphismePolymorphisme via les interfacesVérification de type à l'exécutionLes opérateurs is & asMot-clé covariantRécapitulatif - Processeur de paiement12POO Asynchrone
Futures & async/awaitBases des StreamsStream ControllersConstructeurs asynchronesL'asynchrone dans les méthodes de classeRécapitulatif - Data Fetcher15Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository