Stream là gì?
Lập trình bất đồng bộ là một thuật ngữ phổ biến trong lập trình. Trong ngôn ngữ Dart, Future class để khai báo 1 hàm bất đồng bộ, xử lý các tính toán không được hoàn thành ngay, và thông báo kết quả khi đã sẵn sàng. Stream là 1 luồng sự kiện bất đồng bộ. cho phép chúng ta lắng nghe sự kiện này khi được phát ra từ luồng.
A stream is a sequence of asynchronous events.
Phân loại Stream
Có 2 loại Stream
- Single subscription streams
- Broadcast streams
Single subscription streams: chỉ có thể lắng nghe 1 lần duy nhất. Nếu có sự kiện lắng nghe từ một nơi khác hoặc lắng nghe lại lần 2 trở lên thì sẽ báo lỗi. Để khai báo, chúng ta dùng StreamController().
StreamController streamController = StreamController();
streamController.sink.add(1);
streamController.sink.add(2);
streamController.stream.listen((data) {
print("Listen: $data");
});
streamController.sink.add(3);
streamController.sink.add(4);
Listen: 1
Listen: 2
Listen: 3
Listen: 4
StreamController streamController = StreamController();
streamController.sink.add(1);
streamController.sink.add(2);
streamController.stream.listen((data) {
print("Listen: $data");
});
// Listen: 1
// Listen: 2
// Lắng nghe lại stream
streamController.stream.listen((data) {
print(data);
});
Unhandled exception:
Bad state: Stream has already been listened to.
Broadcast streams: Trái ngược với Single subscription streams, có thể lắng nghe từ bất kỳ đâu. Để khai báo, chúng ta dùng StreamController.broadcast()
StreamController broadcastStreamController = StreamController.broadcast();
broadcastStreamController.stream
.listen((data) => print("Broadcast(1) listen: $data"));
broadcastStreamController.stream
.listen((data) => print("Broadcast(2) listen: $data"));
broadcastStreamController.sink.add(1);
broadcastStreamController.sink.add(2);
broadcastStreamController.sink.add(3);
Broadcast(1) listen: 1
Broadcast(2) listen: 1
Broadcast(1) listen: 2
Broadcast(2) listen: 2
Broadcast(1) listen: 3
Broadcast(2) listen: 3
StreamController broadcastStreamController = StreamController.broadcast();
broadcastStreamController.stream
.listen((data) => print("Broadcast(1) listen: $data"));
broadcastStreamController.sink.add(1);
broadcastStreamController.sink.add(2);
broadcastStreamController.sink.add(3);
broadcastStreamController.stream
.listen((data) => print("Broadcast(2) listen: $data"));
broadcastStreamController.sink.add(4);
Broadcast(1) listen: 1
Broadcast(2) listen: 4
Broadcast(1) listen: 2
Broadcast(1) listen: 3
Broadcast(1) listen: 4
Có thể thấy, Broadcast streams được lắng nghe sau khi phát dữ liệu sẽ không nhận được dữ liệu đã phát trước đó. Còn Single subscription streams sẽ luôn nhận được tất cả dữ liệu vì chỉ tồn tại duy nhất 1 lần lắng nghe.
Tại sao nên sử dụng Stream
- Stream là một thư viện/api core của Dart
- -> Dễ dàng tạo ra các plugin, tách nhỏ repo
- -> Nắm vững công nghệ, dễ sử dụng
- Stream phù hợp với phong cách làm mới giao diện (declarative) của Flutter và mô hình MVVM
- Giảm sự phụ thuộc vào các thư viện bên thứ 3
- Tránh lỗi khi thay đổi version
- Giảm size app
- Một số thư viện có cơ chế phụ thuộc vào Stream như bloc, getx
Xây dựng giao diện bằng StreamBuilder
StreamBuilder dùng để lắng nghe sự thay đổi của Stream và làm mới lại giao diện. Trong thực tế, chúng ta sẽ đặt stream trong ViewController/ViewModel để xử lý và phát dữ liệu, UI sẽ lắng nghe stream và thực hiện rebuild giao diện.
Để sử dụng StreamBuilder cần gọi
const StreamBuilder({
Key? key,
Stream<T>? stream,
T? initialData,
required AsyncWidgetBuilder<T> builder,
})
Ý nghĩa Parameters:
- Stream? stream: Truyền vào stream cần lắng nghe và được xử lý ở hàm builder
- T? initialData: giá trị mặc định, nếu không truyền thì coi như chưa nhận được dữ liệu từ Stream
- required AsyncWidgetBuilder builder: Xây dựng giao diện dựa vào giá trị stream phát ra.
Tham khảo
https://dart.dev/tutorials/language/streams
https://medium.flutterdevs.com/exploring-streambuilder-in-flutter-5958381bca67
[…] Bloc, để nhận event input và phát ra state output, chúng ta cần sử dụng tới Stream Controller để triển khai. Input sẽ được thêm vào sink của StreamController và phía UI […]
[…] là một luồng dữ liệu bất đồng bộ. Mời bạn xem lại bài viết Stream trong Flutter để hiểu rõ hơn về […]