Flutter数据流监听插件stream_watcher的使用
Flutter数据流监听插件stream_watcher的使用
stream_watcher
受Provider
出色的watch
扩展到BuildContext
的启发,此插件为Stream
添加了扩展功能,允许监听流的值,并在更改时自动更新父级小部件。
使用方法
导入包,然后在Stream
上调用.watch(context)
。
import 'package:stream_watcher/stream_watcher.dart';
class Example extends StatefulWidget {
const Example({Key key}) : super(key: key);
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
Stream<double> progressStream;
@override
Widget build(BuildContext context) {
return Center(
child: CircularProgressIndicator(
value: progressStream.watch(context) ?? 0,
),
);
}
}
限制
当使用.watch(...)
方法时,你必须确保所监视的Stream
不会在重建时被重新创建。例如,如果你的流获取器隐式调用了someStream.map(...)
,则会创建一个新的流,初始值为null,这会导致无限循环。
虽然我认为StreamBuilder
也会遇到这个问题,但由于StreamBuilder
会重新构建自身而不是父级小部件,因此这个问题发生的频率较低。
性能
显然,关于这一点最大的问题是性能。不幸的是,它的性能不如普通的StreamBuilder
,但性能损失并不严重。这意味着,虽然你不应该在性能问题严重的情况下使用它,但在大多数情况下它是完全可以接受的。使用.watch(...)
带来的编码简便性也是一个优点,使用.watch(...)
是一种非常方便地访问流值的方式。
包含的示例应用程序包含三种访问流的配置:
StreamBuilder
- 在自己的上下文中使用(使用构建器)的
.watch(...)
- 在具有30个构建器的上下文中使用
.watch(...)
最后一项配置被包括是因为我认为小部件的大小可能会影响性能。当然在这个测试案例中,差异是微不足道的。
在我的三星Galaxy S8上使用性能覆盖层(UI线程)测量计算时间,我们得到(大约 - 最大值尤其变化很大):
方法 | 平均 | 最大 |
---|---|---|
1 | 4.8 毫秒 | 15 毫秒 |
2 | 6.0 毫秒 | 15 毫秒 |
3 | 6.2 毫秒 | 16 毫秒 |
注意事项
watch(...)
函数的实现在一个点上捕获了一个FlutterError
。这并不是一个具体的错误,但可能被认为是不良实践,因为错误应该被修复而不是被捕获。在这种情况下,这是我发现的唯一方法来发现元素是否仍然挂载。
与StreamBuilder
类似,.watch(...)
最初返回一个null
值。我最初包含了一个可选的initialValue
参数,该参数在开始时设置值,但是这仅在BuildContext
中只监视一次流时才有效,因此它被移除了。处理这个null
值的最佳方式是使用空安全操作符someStream.watch(context) ?? backupValue
。
示例代码
import 'package:flutter/material.dart';
import 'data_bloc.dart';
import 'pages/stream_builder_page.dart';
import 'pages/single_widget_page.dart';
import 'pages/builder_widget_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stream Watcher Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final dataBloc = DataBloc(30, Duration(milliseconds: 10));
final titles = [
'StreamBuilder',
'Watch with individual widgets',
'Watch with single widgets',
];
int titleIndex = 0;
@override
void dispose() {
dataBloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(titles[titleIndex]),
),
body: PageView(
onPageChanged: (value) => setState(() {
titleIndex = value;
}),
children: [
StreamBuilderPage(dataBloc: dataBloc),
BuilderWidgetPage(dataBloc: dataBloc),
SingleWidgetPage(dataBloc: dataBloc),
],
),
);
}
}
相关页面代码
// pages/stream_builder_page.dart
import 'package:flutter/material.dart';
import 'data_bloc.dart';
class StreamBuilderPage extends StatelessWidget {
final DataBloc dataBloc;
StreamBuilderPage({required this.dataBloc});
@override
Widget build(BuildContext context) {
return StreamBuilder<double>(
stream: dataBloc.progressStream,
initialData: 0.0,
builder: (context, snapshot) {
return Center(
child: CircularProgressIndicator(value: snapshot.data),
);
},
);
}
}
// pages/builder_widget_page.dart
import 'package:flutter/material.dart';
import 'data_bloc.dart';
class BuilderWidgetPage extends StatelessWidget {
final DataBloc dataBloc;
BuilderWidgetPage({required this.dataBloc});
@override
Widget build(BuildContext context) {
return Center(
child: StreamWatcher<double>(
stream: dataBloc.progressStream,
builder: (context, value) {
return CircularProgressIndicator(value: value ?? 0);
},
),
);
}
}
// pages/single_widget_page.dart
import 'package:flutter/material.dart';
import 'data_bloc.dart';
class SingleWidgetPage extends StatelessWidget {
final DataBloc dataBloc;
SingleWidgetPage({required this.dataBloc});
@override
Widget build(BuildContext context) {
return Center(
child: StreamWatcher<double>(
stream: dataBloc.progressStream,
builder: (context, value) {
return CircularProgressIndicator(value: value ?? 0);
},
),
);
}
}
数据块类
// data_bloc.dart
import 'dart:async';
class DataBloc {
final int itemCount;
final Duration duration;
StreamController<double> _progressController;
Timer _timer;
DataBloc(this.itemCount, this.duration) {
_progressController = StreamController<double>();
_timer = Timer.periodic(duration, (timer) {
double newValue = (_progressController.value + 1 / itemCount) % 1;
_progressController.sink.add(newValue);
});
}
Stream<double> get progressStream => _progressController.stream;
void dispose() {
_progressController.close();
_timer.cancel();
}
}
更多关于Flutter数据流监听插件stream_watcher的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据流监听插件stream_watcher的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
stream_watcher
是一个 Flutter 插件,用于监听和观察数据流(Stream
)的状态和变化。它可以帮助你在 Flutter 应用中更方便地管理和调试数据流。以下是如何使用 stream_watcher
插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 stream_watcher
依赖:
dependencies:
flutter:
sdk: flutter
stream_watcher: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 导入包
在你的 Dart 文件中导入 stream_watcher
包:
import 'package:stream_watcher/stream_watcher.dart';
3. 使用 StreamWatcher
StreamWatcher
可以用来包装任何 Stream
,并监听其状态和事件。
基本用法
import 'package:flutter/material.dart';
import 'package:stream_watcher/stream_watcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: StreamWatcherExample(),
);
}
}
class StreamWatcherExample extends StatefulWidget {
[@override](/user/override)
_StreamWatcherExampleState createState() => _StreamWatcherExampleState();
}
class _StreamWatcherExampleState extends State<StreamWatcherExample> {
Stream<int> _stream;
StreamWatcher<int> _streamWatcher;
[@override](/user/override)
void initState() {
super.initState();
_stream = Stream.periodic(Duration(seconds: 1), (count) => count).take(10);
_streamWatcher = StreamWatcher<int>(_stream);
// 监听流事件
_streamWatcher.listen((event) {
print('Event: $event');
});
// 监听流的完成
_streamWatcher.onDone(() {
print('Stream completed');
});
// 监听流的错误
_streamWatcher.onError((error, stackTrace) {
print('Error: $error');
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stream Watcher Example'),
),
body: Center(
child: StreamBuilder<int>(
stream: _streamWatcher.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('Count: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Waiting for data...');
}
},
),
),
);
}
}