如何从StreamController中获取'data'值?附Flutter代码示例
解决Flutter中StreamController数据在Marker InfoWindow中使用的问题
你的核心问题是异步流数据无法直接同步用于Marker的InfoWindow标题,而且当前代码每次onTap都订阅Stream会导致重复订阅,浪费资源还可能引发内存泄漏。下面给出两种可行的实现方式:
方式一:手动管理Stream订阅与组件状态
使用StatefulWidget维护流数据状态,在组件生命周期内仅订阅一次Stream:
// children.dart 子组件文件 class ChildrenMap extends StatefulWidget { const ChildrenMap({super.key}); @override State<ChildrenMap> createState() => _ChildrenMapState(); } class _ChildrenMapState extends State<ChildrenMap> { String? _streamData; StreamSubscription? _streamSubscription; @override void initState() { super.initState(); // 组件初始化时订阅Stream,仅订阅一次 _streamSubscription = ctrl.stream.listen((data) { // 更新状态,触发组件重建 setState(() { _streamData = data; }); }); } @override void dispose() { // 组件销毁时取消订阅,避免内存泄漏 _streamSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return GoogleMap( onTap: (LatLng latlng) { // 直接使用已保存的_streamData创建Marker Marker( position: latlng, infoWindow: InfoWindow( title: _streamData ?? '默认标题', // 用空值运算符处理未收到数据的情况 ), // 补充Marker的其他必要属性 ); }, // ...GoogleMap的其他属性 ); } }
方式二:使用StreamBuilder自动管理订阅
StreamBuilder会自动处理Stream的订阅与取消,无需手动管理生命周期:
// children.dart 子组件文件 GoogleMap( onTap: (LatLng latlng) { // 用StreamBuilder包裹Marker,自动响应Stream数据变化 StreamBuilder( stream: ctrl.stream, initialData: '默认标题', // 设置初始标题,可选 builder: (context, snapshot) { String title = '默认标题'; if (snapshot.hasData) { title = snapshot.data.toString(); } return Marker( position: latlng, infoWindow: InfoWindow(title: title), // 补充Marker的其他必要属性 ); }, ); }, // ...GoogleMap的其他属性 );
注意事项
- 绝对不要在
onTap回调内重复调用ctrl.stream.listen(),每次调用都会创建新的订阅,可能导致多次打印重复数据,还会引发内存泄漏。 - 如果你的全局StreamController不再使用,记得调用
ctrl.close()释放资源。
内容的提问来源于stack exchange,提问作者Ae Gg
相关产品推荐
相关产品推荐

