Flutter中如何停止/取消Stream.periodic,计数到0时终止流运行
解决方案
1、停止Stream.periodic运行的实现方式
你不需要通过抛异常的方式终止流,更简洁可靠的实现有两种:
方案1:使用take方法自动终止流(推荐)
take方法可以指定流最多发射的事件数量,达到数量后流会自动关闭,刚好适配倒计时场景:倒计时从val到0总共要发射val+1次事件,直接配置take(val+1)即可,不需要额外写终止逻辑:
Stream<int> stream(int val) { return Stream.periodic(const Duration(seconds: 1), (int i) { return val - i; }).take(val + 1); }
流终止时会自动触发AsyncSnapshot的done状态,你可以在StreamBuilder的builder回调里判断snapshot.connectionState == ConnectionState.done来做倒计时结束后的逻辑。
方案2:通过StreamController手动控制终止
如果你需要在任意时机手动停止流(比如用户主动点击暂停倒计时),可以用StreamController包装流,需要停止时调用controller.close()即可:
首先需要把页面改为StatefulWidget,保存StreamController实例:
class MyHomePage1 extends StatefulWidget { @override State<MyHomePage1> createState() => _MyHomePage1State(); } class _MyHomePage1State extends State<MyHomePage1> { late final StreamController<int> _controller; @override void initState() { super.initState(); const countDownVal = 20; _controller = StreamController<int>(); Stream.periodic(const Duration(seconds: 1), (i) { final ret = countDownVal - i; if (ret == 0) { _controller.close(); // 计数到0时关闭流,自动停止Stream.periodic } return ret; }).listen((event) { if (!_controller.isClosed) { _controller.add(event); } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("APP DEMO"), ), body: Center( child: StreamBuilder( stream: _controller.stream, builder: (context, AsyncSnapshot<int> snapshot) { if (snapshot.hasError) { debugPrint("error code "); return const Text('倒计时出错'); } if (!snapshot.hasData) { return const Text('加载中', style: TextStyle(fontSize: 20)); } return Text('Timer: ${snapshot.data}', style: const TextStyle(fontSize: 20)); }), ), ); } @override void dispose() { _controller.close(); // 页面销毁时关闭控制器释放资源 super.dispose(); } }
2、StreamBuilder监听器的销毁逻辑
- 默认场景下不需要你手动销毁StreamBuilder的监听器:StreamBuilder本身会监听组件的生命周期,当组件被移除销毁时,会自动取消对流的订阅,不会产生内存泄漏。
- 如果你自己创建了StreamController、或者手动调用了
stream.listen()保存了StreamSubscription实例,就必须在组件的dispose生命周期方法里手动调用controller.close()或者subscription.cancel()释放资源,否则会产生内存泄漏,具体实现可以参考上面方案2的dispose方法代码。
内容的提问来源于stack exchange,提问作者AnhTuan
相关产品推荐
相关产品推荐

