Flutter từ RxDart đến Bloc Pattern, phần 1: Stream và giải thích các thuật ngữ

Tram Ho

Lời mở đầu

Mình viết series này với mục đích chia sẻ kiến thức về Bloc Pattern trong Flutter. Vì nó có liên quan đến các kiến thức về lập trình bất đồng bộ như Stream nên mình quyết định sẽ đi từ gốc cho đến ngọn

Series này sẽ gồm 3 nội dung chính:

Phần 1: Stream, các khái niệm liên quan đến Stream như Stream Controller, Subscription,… Bởi vì hiểu được Stream thì mới có thể hiểu được RxDart và Bloc Pattern. Nếu bạn đã hiểu các khái niệm về Stream mời bạn đến thẳng các phần tiếp theo của series này.

Phần 2: RxDart (cần kiến thức về Stream trong phần 1)

Phần 3: Bloc Pattern (cần kiến thức về Stream trong phần 1)

Okay, bây giờ chúng ta sẽ bắt đầu với phần 1 là Sờ tream.

1. Stream là gì, Event là gì

Có thể hình dung cái băng chuyền này là 1 Stream.

Định nghĩa nguyên văn từ doc:

A stream is a sequence of asynchronous events

Dịch nôm na ra thì Stream là một chuỗi các events bất đồng bộ. Các khối hộp đang trượt trên băng kia chính là các events. Event có thể là một data, cũng có thể là một error, hoặc một trạng thái done (Trong phần Tạo ra Stream ở dưới mình sẽ nói rõ hơn). Các events này được xử lý bất đồng bộ. Như vậy Stream là một chuỗi các events được xử lý bất đồng bộ.

Thực tế Stream nó không có chạy mãi như cái ảnh gif đâu nha. Nó có thể được tạo ra, cũng có thể bị đóng lại và ta cũng có thể tạm dừng cái băng chuyền đó (pause) và tiếp trục cho băng chuyền chạy (resume)

Trong quá trình truyền data, có thể qua 1 số khâu chế biến trung gian trước khi đến tay Consumer. Như cái ảnh dưới đây, dữ liệu đầu vào là các chữ thường qua một hàm xử lý gọi là map để cho ra những data đầu ra là các chữ in hoa. Các hàm như vậy thì trong lớp Stream của Dart cũng có tuy nhiên còn hạn chế. Chính vì vậy mà chúng ta mới cần đến RxDart – một thư viện bổ sung sức mạnh thêm cho Stream.

Nếu các bạn đã từng biết RxJava hay RxJs,… thì định nghĩa Stream chính là định nghĩa của Observable trong Rx.

2. Tạo ra Stream, lắng nghe Stream và giải thích thuật ngữ

emit là gì

Hành động phát ra Event của Stream người ta gọi là emit

Tạo Stream

Có rất là nhiều cách để tạo ra 1 stream. Ở đây mình tạm giới thiệu 1 cách đơn giản nhất để giải thích thuật ngữ.

Ở đây mình đã tạo ra 1 Stream và emit 1 data là ‘gấu bông’ nhưng khi run chương trình thì sẽ ko xảy ra gì cả. Là vì mình phát ra con ‘gấu bông’ nhưng không có ai nhận hết. Muốn nhận được con gấu bông phải đăng ký Stream để được nhận nó khi ‘gấu bông’ được phát ra. Tiếp theo chúng ta sẽ tiến hành đăng ký Stream trên (subscribe a Stream).

Subscribe một Stream

Chúng ta sử dụng hàm listen để đăng ký nhận events từ stream.

Output:

Trong RxJava, …, người ta còn gọi cái lambda này (event) { print('Tôi đã nhận được $event'); } là 1 Observer

Trong hàm listen chúng ta có thêm các optional parameter như onDone, onError

Một Stream khi emit xong tất cả event thì nó sẽ emit event tại onDone, nếu gặp lỗi thì nó sẽ emit một error và onError sẽ giúp ta nhận được event đó.

Output: Do không gặp lỗi nên output sẽ là thế này.

Thêm nhiều cách tạo Stream

Bây giờ mình sẽ giới thiệu thêm nhiều cách tạo ra Stream nữa:

  • Tạo ra một Stream đồng thời emit 1 error và done luôn.

Output:

  • Tạo ra một Stream đồng thời emit 1 List data xong rồi Done.

Output:

  • Tạo ra một Stream từ 1 Future.

Output:

  • Tạo ra một stream cứ 1 giây sẽ emit ra 1 event. Các bạn chú ý là error nó cũng là event nên khi Stream emit ra error thì Stream đó không dừng lại.

Output:

Stream này nó bất tử lun. Bây giờ mình sẽ sử dụng StreamSubscription để trảm nó, không cho nó bất tử nữa!

3. StreamSubscription là gì

Hàm listen ở trên sẽ trả về một đối tượng StreamSubscription. StreamSubscription giúp ta điều khiển stream. Ta có thể pause stream, resume stream và hủy stream.

Output:

Và chúng ta đã có thể stop được stream bất tử ở trên thành công bằng hàm cancel(). Người ta thường gọi hành động này là unsubscribe một Stream.

4. Stream Builder, async*, yield và yield*

Trong thực tế, người ta lại rất ít khi dùng các cách trên để tạo stream mà họ sử dụng cái gọi là stream builder, ở đó họ có thể emit data bất cứ thời điểm nào họ muốn.

Để tạo một stream builder ta tạo 1 function với async* và trả về một Stream. Để emit một data ta có thể sử dụng yield, để emit tất cả data trong 1 stream ta có thể sử dụng yield*

Output:

Kết luận

Qua phần 1 của series này, hy vọng các bạn đã nắm được các thuật ngữ quan trọng trong Stream cũng như trong lập trình bất đồng bộ của Dart. Các thuật ngữ này rất quan trọng đối với loạt bài tiếp theo trong series này. Trong bài tiếp theo mình sẽ giới thiệu đến các bạn các toán tử của Stream và Stream Controller, Broadcast Stream. Hy vọng các bạn đón đọc.

Nguồn tham khảo: https://dart.dev/tutorials/language/streams

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo