Stream di Dart
Data yang mengalir terus: Stream, listen, await for, dan broadcast stream.
Dari Future ke Stream
Future memberikan satu nilai di masa depan. Tapi bagaimana dengan data yang datang berulang-ulang? Update lokasi GPS, pesan chat masuk, harga saham berubah: ini butuh Stream, yaitu aliran nilai sepanjang waktu.
Stream<int> hitungMundur() async* {
for (int i = 3; i >= 1; i--) {
await Future.delayed(Duration(seconds: 1));
yield i; // kirim nilai ke pendengar, lalu lanjut
}
}
void main() async {
await for (var angka in hitungMundur()) {
print(angka); // 3... 2... 1... (tiap detik)
}
print('Mulai!');
}async*(bintang) menandai fungsi generator streamyieldmengirim satu nilai ke stream tanpa menghentikan fungsiawait formendengarkan sampai stream selesai
listen: cara manual
Stream<int> angka() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(milliseconds: 300));
yield i;
}
}
void main() {
angka().listen(
(data) => print('Dapat: $data'),
onDone: () => print('Stream selesai'),
onError: (e) => print('Error: $e'),
);
}listen() mengembalikan StreamSubscription yang bisa di-cancel. Di Flutter, subscription yang lupa di-cancel adalah sumber memory leak klasik.
Mengubah stream: map, where
Stream punya operator mirip List:
Stream<int> angka() async* {
for (int i = 1; i <= 6; i++) {
yield i;
}
}
void main() async {
await for (var x in angka().where((n) => n.isEven).map((n) => n * 10)) {
print(x); // 20, 40, 60
}
}Ada juga operator lanjutan seperti debounce (di package rxdart) untuk menunda sampai user berhenti mengetik, sangat berguna untuk search-as-you-type.
Catatan teknis: Secara default stream itu single-subscription: cuma boleh didengarkan sekali.
listenkedua akan error "Stream has already been listened to". Kalau butuh banyak pendengar (mis. beberapa widget mendengar data yang sama), ubah jadi broadcast stream dengan.asBroadcastStream(). Tapi ingat: broadcast stream tidak menyimpan event yang lewat sebelum ada pendengar.
StreamController: bikin stream sendiri
Kadang kamu yang memproduksi event, bukan sekadar mendengar:
import 'dart:async';
void main() async {
var controller = StreamController<String>();
controller.stream.listen((pesan) => print('Chat: $pesan'));
controller.add('Halo!');
controller.add('Apa kabar?');
await Future.delayed(Duration(milliseconds: 100));
await controller.close();
}StreamController punya dua sisi: add() untuk mengirim, stream untuk didengar. Pola ini adalah fondasi BLoC, salah satu state management paling populer di Flutter.
Stream di Flutter: StreamBuilder
Alasan stream wajib dipelajari: Flutter punya widget StreamBuilder yang otomatis rebuild UI setiap ada data baru. Chat realtime, live score, sensor: semuanya stream di balik layar. Memahami konsepnya di Dart murni membuat StreamBuilder terasa natural, bukan sihir.
Kapan Future, kapan Stream?
| Situasi | Pakai |
|---|---|
| Ambil data sekali (HTTP GET) | Future |
| Data datang berulang (chat, sensor) | Stream |
| Progress upload/download | Stream |
| Simpan ke database | Future |
Aturan praktis: kalau operasinya punya "selesai" yang jelas dan satu hasil, Future cukup. Kalau datanya mengalir terus tanpa akhir yang pasti, pakai Stream.