Flutter数据流监听插件stream_listener_widget的使用
Flutter数据流监听插件stream_listener_widget的使用
stream_listener_widget
是一个简单的Widget,用于监听Stream而不重建其子组件(例如显示对话框)。
简单保持
- 逻辑类(ViewModel、Controller等)不应该使用BuildContext。
- 触发弹出窗口或导航属于视图(View)的责任。
StreamListener
Widget与Flutter的StreamBuilder
Widget一样简单。
- 它允许你响应Stream事件而无需重建任何Widget。
- 它会为你清理内存,取消所有给定Stream的订阅。
以下是一个例子,我们的逻辑类仅触发一些事件,这些事件由视图处理以进行导航或显示错误对话框。
class MyView extends StatelessWidget {
final MyController logic;
const MyView({super.key, required this.logic});
void _onLoginSuccess(LoginSuccess e) {
Navigator.of(context).pushNamed('/homePage');
}
void _onError(LoginError e) {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Dialog(child: Text('An unknown error occurred')),
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return StreamListener(
listeners: [
(context) => logic.controller.stream.whereType<LoginSuccess>().listen(_onLoginSuccess),
(context) => logic.controller.stream.whereType<LoginError>().listen(_onError),
],
child: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => logic.submitForm('my_email', 'my_password'),
child: const Text('Submit'),
),
),
);
}
}
/// 这里定义了一些类型类来表示可能的领域/逻辑事件
sealed class MyEvent {}
class LoginSuccess extends MyEvent {}
class LoginError extends MyEvent {}
- 我们的视图处理视图逻辑。
- 我们的逻辑类处理业务逻辑。
- 责任和依赖关系被很好地分离。
- 我们的控制器进行了领域驱动设计,可以用于其他地方。
- 通过定义一个类型的逻辑事件,业务逻辑更加清晰。
- 代码稳定且可测试。
以下是你应该避免的做法(在逻辑类中处理导航、弹窗等):
class MyController {
BuildContext context;
Future<void> submitForm(String email, String password) async {
try {
await authenticationApi.login(email, password);
Navigator.of(context).pushNamed('/homePage');
} catch (e) {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Dialog(child: Text('An unknown error occurred')),
);
}
}
}
class MyView extends StatefulWidget {
final logic = MyController();
const MyView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
logic.context = context; // 这真的很难看
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => logic.submitForm('my_email', 'my_password'),
child: const Text('Submit'),
),
);
}
}
但是等等?上面的例子更短!
- 是的!但我们没有将视图逻辑和业务逻辑分开。
- 我们的控制器做了一切,而视图什么也不做。
- 责任和依赖关系混在一起了。
- 你的控制器是为特定的视图设计的。
- BuildContext在Future/异步间隔后被使用,这是禁止的,因为它可能是不稳定的。
示例代码
main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:stream_listener_widget/stream_listener_widget.dart';
void main() => runApp(const MaterialApp(home: CounterView()));
class CounterView extends StatefulWidget {
const CounterView({super.key});
[@override](/user/override)
State<CounterView> createState() => _CounterViewState();
}
class _CounterViewState extends State<CounterView> {
final logic = CounterLogic();
void _onMaxReached(int state) {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('Your counter: $state has reached or exceeded max'),
),
);
},
);
}
[@override](/user/override)
void dispose() {
logic.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return StreamListener(
listeners: [
(context) => logic.maxReached.listen(_onMaxReached),
],
child: Scaffold(
appBar: AppBar(title: const Text('Counter demo')),
body: Center(
child: StreamBuilder(
initialData: logic.state,
stream: logic.controller.stream,
builder: (context, snapshot) => Text('Counter: ${snapshot.data}'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: logic.increment,
child: const Icon(Icons.add),
),
),
);
}
}
class CounterLogic {
int state = 0;
final controller = StreamController<int>.broadcast();
Stream<int> get maxReached => controller.stream.where((e) => e >= 5);
void increment() => controller.add(++state);
void dispose() => controller.close();
}
更多关于Flutter数据流监听插件stream_listener_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据流监听插件stream_listener_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter中使用stream_listener_widget
插件进行数据流监听的代码示例。stream_listener_widget
插件是一个方便的工具,用于简化对Dart Streams的监听和处理。虽然这不是一个官方的Flutter插件,但假设它提供了类似的功能,我们可以编写一个示例来展示其基本用法。
首先,确保你已经在pubspec.yaml
文件中添加了stream_listener_widget
依赖(如果这是一个真实存在的插件):
dependencies:
flutter:
sdk: flutter
stream_listener_widget: ^x.y.z # 替换为实际版本号
然后,运行flutter pub get
来获取依赖。
接下来,我们可以编写一个示例应用,展示如何使用这个插件来监听一个Stream。
示例代码
import 'package:flutter/material.dart';
import 'package:stream_listener_widget/stream_listener_widget.dart'; // 假设插件提供这个导入路径
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stream Listener Widget Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamListenerDemo(),
);
}
}
class StreamListenerDemo extends StatefulWidget {
@override
_StreamListenerDemoState createState() => _StreamListenerDemoState();
}
class _StreamListenerDemoState extends State<StreamListenerDemo> {
final StreamController<String> _controller = StreamController<String>();
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stream Listener Widget Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
StreamListenerWidget<String>(
stream: _controller.stream,
onData: (data) {
return Text(
'Stream Data: $data',
style: TextStyle(fontSize: 24),
);
},
onError: (error) {
return Text(
'Stream Error: $error',
style: TextStyle(fontSize: 24, color: Colors.red),
);
},
onDone: () {
return Text(
'Stream Done',
style: TextStyle(fontSize: 24),
);
},
loading: CircularProgressIndicator(),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
_controller.add('Button pressed');
},
child: Text('Press Me'),
),
],
),
),
);
}
}
解释
- 依赖导入:假设
stream_listener_widget
插件提供了一个简单的导入路径。 - Stream 控制:我们使用
StreamController
来创建一个Stream,用于发送数据事件。 - StreamListenerWidget:这是我们的核心组件,用于监听Stream并显示数据。
stream
:指定要监听的Stream。onData
:当Stream发送数据时调用的构建函数。onError
:当Stream发生错误时调用的构建函数。onDone
:当Stream结束时调用的构建函数。loading
:在Stream开始但尚未发送数据时显示的Widget。
- 按钮:一个按钮,每次按下时都会向Stream发送一个数据事件。
请注意,这个示例代码是基于假设stream_listener_widget
插件存在的。如果这是一个虚构的插件或者你有具体的插件实现细节,请根据实际情况调整代码。如果插件不存在,你可以考虑使用Flutter内置的StreamBuilder
来实现类似的功能。