Trong Flutter, Stream là một khái niệm quan trọng trong lập trình bất đồng bộ, cho phép bạn xử lý và nhận dữ liệu theo thời gian thực. Streams rất hữu ích khi bạn cần làm việc với các nguồn dữ liệu có thể phát sinh nhiều giá trị qua thời gian, chẳng hạn như dữ liệu từ mạng, cơ sở dữ liệu, hoặc các sự kiện từ người dùng. Bài viết này sẽ giải thích chi tiết về Stream, cách hoạt động của nó, và cách sử dụng trong Flutter.

Stream trong Flutter là gì?

Stream là một cách để xử lý dữ liệu bất đồng bộ bằng cách phát ra một chuỗi các giá trị theo thời gian. Mỗi giá trị được phát ra có thể được xử lý ngay lập tức hoặc sau đó, tùy thuộc vào cách mà bạn đăng ký để nhận chúng. Stream có thể phát ra nhiều giá trị và có thể kết thúc hoặc xảy ra lỗi trong quá trình phát.

Cấu trúc của Stream

Mỗi Stream có thể được coi là một tập hợp các sự kiện mà bạn có thể lắng nghe. Bạn có thể nghĩ về nó như một “đường ống” mà qua đó dữ liệu được truyền đi. Có hai loại streams chính trong Dart:

  1. Single-Subscription Stream: Đây là loại stream phổ biến nhất, trong đó chỉ có một listener có thể đăng ký để nhận các sự kiện. Loại stream này thích hợp cho các tình huống mà bạn cần xử lý dữ liệu từ một nguồn dữ liệu cụ thể.
  2. Broadcast Stream: Đây là loại stream cho phép nhiều listener cùng đăng ký để nhận các sự kiện. Loại stream này thường được sử dụng trong các tình huống mà bạn cần phát các sự kiện cho nhiều listener cùng một lúc, chẳng hạn như các sự kiện từ UI hoặc các cập nhật từ cơ sở dữ liệu.

Cách sử dụng Stream

Để sử dụng Stream trong Flutter, bạn có thể sử dụng lớp StreamController, cho phép bạn tạo và quản lý một stream. Dưới đây là một ví dụ đơn giản minh họa cách tạo và sử dụng stream trong Flutter.

Ví dụ về Stream

import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: StreamExample(),
    );
  }
}

class StreamExample extends StatefulWidget {
  @override
  _StreamExampleState createState() => _StreamExampleState();
}

class _StreamExampleState extends State<StreamExample> {
  late StreamController<int> _streamController;
  late Stream<int> _stream;

  @override
  void initState() {
    super.initState();
    _streamController = StreamController<int>();
    _stream = _streamController.stream;

    // Phát ra giá trị từ 0 đến 9
    int count = 0;
    Timer.periodic(Duration(seconds: 1), (timer) {
      if (count < 10) {
        _streamController.add(count);
        count++;
      } else {
        _streamController.close(); // Đóng stream khi hoàn tất
        timer.cancel();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Stream Example")),
      body: Center(
        child: StreamBuilder<int>(
          stream: _stream,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return CircularProgressIndicator();
            } else if (snapshot.hasError) {
              return Text("Error: ${snapshot.error}");
            } else if (snapshot.hasData) {
              return Text("Count: ${snapshot.data}");
            } else {
              return Text("No data");
            }
          },
        ),
      ),
    );
  }

  @override
  void dispose() {
    _streamController.close(); // Đảm bảo đóng stream khi không còn sử dụng
    super.dispose();
  }
}

Giải thích mã

  • StreamController: Đầu tiên, chúng ta tạo một StreamController<int> trong hàm initState(), điều này cho phép chúng ta phát ra các giá trị kiểu int.
  • Timer: Sử dụng Timer.periodic, chúng ta phát ra các giá trị từ 0 đến 9 mỗi giây. Khi count đạt đến 10, chúng ta đóng stream bằng cách gọi close() trên _streamController.
  • StreamBuilder: Chúng ta sử dụng StreamBuilder<int> để xây dựng giao diện người dùng dựa trên dữ liệu nhận được từ stream. StreamBuilder sẽ tự động cập nhật giao diện khi có giá trị mới được phát ra từ stream.
  • dispose: Cuối cùng, trong hàm dispose(), chúng ta đóng StreamController để giải phóng tài nguyên.

Kết luận

Stream trong Flutter là một công cụ mạnh mẽ cho phép bạn xử lý dữ liệu bất đồng bộ và cập nhật giao diện người dùng theo thời gian thực. Bằng cách sử dụng StreamControllerStreamBuilder, bạn có thể dễ dàng phát ra và lắng nghe các giá trị từ nhiều nguồn khác nhau. Việc hiểu rõ cách hoạt động của Stream sẽ giúp bạn xây dựng các ứng dụng Flutter mượt mà và hiệu quả hơn, cải thiện trải nghiệm người dùng. Hãy thử áp dụng các kiến thức này vào dự án của bạn để nâng cao khả năng quản lý dữ liệu bất đồng bộ.