flutter 流(Stream)介绍&结合RxDart使用

在 Flutter 中,Stream 是一种用于处理异步数据序列的机制。它允许你以异步的方式接收和处理一系列的数据,类似于事件流。下面将详细介绍 Flutter 中 Stream 的使用,包括创建、监听、转换和控制等方面。

Flutter 流(Stream)介绍

1、创建 Stream

在 Flutter 中有多种方式可以创建 Stream,下面是几种常见的创建方式:

使用 StreamController

StreamController 是创建 Stream 的最常用方式,它允许你手动添加数据到流中。

csharp 复制代码
import 'dart:async';

void main() {
  // 创建一个 StreamController
  final streamController = StreamController<int>();

  // 获取 Stream
  final stream = streamController.stream;

  // 向流中添加数据
  streamController.sink.add(1);
  streamController.sink.add(2);
  streamController.sink.add(3);

  // 监听流
  stream.listen((data) {
    print('Received data: $data');
  });

  // 关闭 StreamController
  streamController.close();
}
使用 Stream.fromIterable

Stream.fromIterable 可以将一个可迭代对象(如 List)转换为 Stream

ini 复制代码
import 'dart:async';

void main() {
  final list = [1, 2, 3, 4, 5];
  final stream = Stream.fromIterable(list);

  stream.listen((data) {
    print('Received data: $data');
  });
}
使用 Stream.periodic

Stream.periodic 可以创建一个按指定时间间隔重复发送数据的 Stream

dart 复制代码
import 'dart:async';

void main() {
  final stream = Stream.periodic(Duration(seconds: 1), (count) => count);

  final subscription = stream.listen((data) {
    print('Received data: $data');
    if (data >= 5) {
      // 取消订阅
      subscription.cancel();
    }
  });
}

在上述代码中,创建了一个每隔 1 秒发送一次数据的 Stream,数据从 0 开始递增。当接收到的数据大于等于 5 时,取消订阅。

2、监听 Stream

使用 listen 方法可以监听 Stream 中的数据,listen 方法接受一个回调函数,当有新的数据到达时,该回调函数将被调用。

dart 复制代码
import 'dart:async';

void main() {
  final stream = Stream.fromIterable([1, 2, 3]);

  stream.listen(
    (data) {
      print('Received data: $data');
    },
    onError: (error) {
      print('Error: $error');
    },
    onDone: () {
      print('Stream is done');
    },
  );
}

在上述代码中,listen 方法接受三个可选参数:

  • onData:当有新的数据到达时调用。
  • onError:当流中出现错误时调用。
  • onDone:当流关闭时调用

3、 转换 Stream

可以使用 Stream 的各种转换方法对数据进行处理,例如 mapwhere 等。

使用 map 转换数据
ini 复制代码
import 'dart:async';

void main() {
  final stream = Stream.fromIterable([1, 2, 3]);

  final transformedStream = stream.map((data) => data * 2);

  transformedStream.listen((data) {
    print('Transformed data: $data');
  });
}
使用 where 过滤数据
ini 复制代码
import 'dart:async';

void main() {
  final stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  final filteredStream = stream.where((data) => data % 2 == 0);

  filteredStream.listen((data) {
    print('Filtered data: $data');
  });
}

4、控制 Stream

可以使用 StreamSubscription 对象来控制 Stream 的监听,例如暂停、恢复和取消订阅。

ini 复制代码
import 'dart:async';

void main() {
  final stream = Stream.periodic(Duration(seconds: 1), (count) => count);

  final subscription = stream.listen((data) {
    print('Received data: $data');
    if (data == 2) {
      // 暂停订阅
      subscription.pause();
      Future.delayed(Duration(seconds: 3), () {
        // 恢复订阅
        subscription.resume();
      });
    }
    if (data >= 5) {
      // 取消订阅
      subscription.cancel();
    }
  });
}

结合RxDart封装

Stream可以简单的处理数据流,但遇到更复杂的需求时,发现原生Stream的操作符不够用。这个时候我们就可以借助于RxDart。RxDart可以提供更多的操作符的链式调用、错误处理、流的组合。

csharp 复制代码
class RxStream<T> {
  final BehaviorSubject<T> _subject = BehaviorSubject<T>();

  Stream<T> get stream => _subject.stream;

  // 添加数据
  void add(T value) => _subject.sink.add(value);

  // 链式操作符示例:防抖 + 过滤空值
  Stream<T> debounceAndFilter(Duration duration) {
    return stream
        .debounceTime(duration) // 防抖
        .where((value) => value != null); // 过滤空值
  }

  // 合并多个流(例如:搜索输入 + 筛选条件)
  static Stream<R> combineStreams<A, B, R>(
      Stream<A> streamA,
      Stream<B> streamB,
      R Function(A, B) combiner,
      ) {
    return Rx.combineLatest2(streamA, streamB, combiner);
  }

  // 关闭资源
  void dispose() => _subject.close();
}
 
场景 1:实时搜索防抖
arduino 复制代码
class SearchService {
  final RxStream<String> _searchStream = RxStream();
  Stream<String> get searchResults => _searchStream.debounceAndFilter(Duration(milliseconds: 300));
  void onSearchTextChanged(String text) {
    _searchStream.add(text);
  }
  void dispose() => _searchStream.dispose();
}

// 使用示例
final searchService = SearchService();
searchService.searchResults.listen((text) {
// 发起搜索请求(防抖后)
print('Searching for: $text');
});
场景 2:数据流合并
less 复制代码
class _MyHomePageState extends State<MyHomePage> {
  late EnhancedRxStream<String> searchStream;
  late EnhancedRxStream<String> filterStream;
  late Stream<String> combinedStream;

  @override
  void initState() {
    super.initState();
    searchStream = EnhancedRxStream<String>();
    filterStream = EnhancedRxStream<String>();

    // 使用 combineStreams 方法合并两个流
    combinedStream = EnhancedRxStream.combineStreams(
      searchStream.stream,
      filterStream.stream,
      (searchTerm, filterTerm) {
        return '搜索词: $searchTerm, 筛选条件: $filterTerm';
      },
    );
  }

  @override
  void dispose() {
    searchStream.dispose();
    filterStream.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Combine Streams Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: TextField(
                onChanged: (text) {
                  searchStream.add(text);
                },
                decoration: const InputDecoration(
                  hintText: '输入搜索词',
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: TextField(
                onChanged: (text) {
                  filterStream.add(text);
                },
                decoration: const InputDecoration(
                  hintText: '输入筛选条件',
                ),
              ),
            ),
            const SizedBox(height: 20),
            StreamBuilder<String>(
              stream: combinedStream,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text(
                    snapshot.data!,
                    style: Theme.of(context).textTheme.headline6,
                  );
                }
                return const Text('暂无数据');
              },
            ),
          ],
        ),
      ),
    );
  }
}
相关推荐
sun0077001 小时前
android ndk编译valgrind
android
AI视觉网奇2 小时前
android studio 断点无效
android·ide·android studio
jiaxi的天空2 小时前
android studio gradle 访问不了
android·ide·android studio
No Silver Bullet3 小时前
android组包时会把从maven私服获取的包下载到本地吗
android
catchadmin3 小时前
PHP serialize 序列化完全指南
android·开发语言·php
星秋Eliot3 小时前
Flutter多线程
flutter·async/await·isolate·flutter 多线程
tangweiguo030519875 小时前
Kable使用指南:Android BLE开发的现代化解决方案
android·kotlin
农夫三拳_有点甜7 小时前
Flutter Assets & Media
flutter
00后程序员张7 小时前
iOS App 混淆与资源保护:iOS配置文件加密、ipa文件安全、代码与多媒体资源防护全流程指南
android·安全·ios·小程序·uni-app·cocoa·iphone
柳岸风9 小时前
Android Studio Meerkat | 2024.3.1 Gradle Tasks不展示
android·ide·android studio