在 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
的各种转换方法对数据进行处理,例如 map
、where
等。
使用 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('暂无数据');
},
),
],
),
),
);
}
}