Menu
CoddyTech

Cơ bản về Stream

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 77 trên 110.

Trong khi Future trả về một giá trị duy nhất, Stream trả về một chuỗi giá trị theo thời gian. Hãy hình dung nó như một đường ống có thể phát ra nhiều phần dữ liệu, rất phù hợp với các sự kiện, bản cập nhật theo thời gian thực hoặc xử lý dữ liệu từng phần.

Bạn có thể tạo một stream đơn giản bằng Stream.fromIterable() hoặc một hàm tạo bất đồng bộ với async* và yield:

Stream<int> countToThree() async* {
  yield 1;
  yield 2;
  yield 3;
}

Future<void> main() async {
  await for (var number in countToThree()) {
    print(number);
  }
}
// Đầu ra: 1, 2, 3

Từ khóa async* đánh dấu một hàm trả về Stream, còn yield phát ra từng giá trị. Để nhận dữ liệu từ stream, hãy dùng await for, câu lệnh này xử lý từng giá trị khi giá trị đó đến.

Bạn cũng có thể nghe một luồng bằng phương thức listen(), phương thức này nhận một hàm callback:

Stream<String> greetings() async* {
  yield 'Hello';
  yield 'Hi';
  yield 'Hey';
}

void main() {
  greetings().listen((message) {
    print(message);
  });
}

Điểm khác biệt chính so với Future: Future hoàn tất một lần với một giá trị duy nhất, còn Stream có thể phát ra nhiều giá trị trước khi hoàn tất. Vì vậy, Stream rất phù hợp để xử lý dữ liệu liên tục như tương tác của người dùng, số liệu cảm biến hoặc dữ liệu đến theo từng phần.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống đếm ngược phát ra các giá trị theo thời gian bằng stream! Bạn sẽ tạo một lớp tạo ra dãy số đếm ngược, qua đó tìm hiểu cách stream gửi nhiều giá trị thay vì chỉ một giá trị.

Bạn sẽ sắp xếp code thành hai tệp:

  • countdown.dart: Tạo lớp Countdown để tạo các stream đếm ngược. Lớp của bạn cần có:
    • Một trường start (int) lưu số bắt đầu đếm ngược
    • Một hàm khởi tạo nhận số bắt đầu
    • Một phương thức countDown() trả về một Stream<int>. Dùng async* và yield để phát ra các số từ start giảm dần đến 0 (bao gồm cả 0)
    • Một phương thức countDownWithMessage() trả về một Stream<String>. Phương thức này cần phát ra các chuỗi theo định dạng 'T-minus [number]' cho mỗi số từ start giảm dần đến 1, sau đó phát ra 'Liftoff!' làm giá trị cuối cùng
  • main.dart: Nhập tệp đếm ngược và minh họa cả hai phương thức stream. Hàm main của bạn cần có từ khóa async và:
    • Tạo một đối tượng Countdown bắt đầu từ 3
    • In ra Number countdown:
    • Dùng await for để lặp qua countDown() và in ra từng số
    • In ra một dòng trống
    • In ra Launch sequence:
    • Dùng await for để lặp qua countDownWithMessage() và in ra từng thông báo

Hãy chú ý cách mỗi câu lệnh yield phát ra một giá trị qua stream, còn await for xử lý từng giá trị khi nó đến. Khác với Future chỉ trả về một kết quả, các stream của bạn sẽ phát ra nhiều giá trị theo thứ tự!

Đầu ra dự kiến:

Number countdown:
3
2
1
0

Launch sequence:
T-minus 3
T-minus 2
T-minus 1
Liftoff!

Tự làm thử

import 'countdown.dart';

Future<void> main() async {
  // TODO: Tạo một instance của Countdown bắt đầu từ 3
  
  // TODO: In ra 'Number countdown:'
  
  // TODO: Dùng await for để lặp qua countDown() và in ra từng số
  
  // TODO: In ra một dòng trống
  
  // TODO: In ra 'Launch sequence:'
  
  // TODO: Dùng await for để lặp qua countDownWithMessage() và in ra từng thông báo
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online