Flutter中StreamBuilder结合HTTP请求使用无法更新数据问题求助
问题根因与修复方案
核心问题
你当前实现的Stream仅会发射1次数据就进入终止状态,没有持续拉取接口更新数据的逻辑,同时StreamBuilder的状态处理逻辑存在错误。
具体问题点
- Stream生成器
listMarkers仅执行1次接口请求就结束,无定时拉取逻辑,无法产生新数据 - StreamBuilder的连接状态判断逻辑错位,waiting状态无对应处理,没有错误捕获逻辑,接口请求失败会直接崩溃
- 接口请求方法依赖外部全局列表,存在并发修改风险
- 每次页面重绘都会重新创建新的Stream实例,造成资源浪费
修复代码
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner:false, title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({ Key? key }) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late Stream<List<Coordonnees>> _markerStream; @override void initState() { super.initState(); _markerStream = listMarkers; } @override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder( stream: _markerStream, builder: (BuildContext context,AsyncSnapshot<List<Coordonnees>> snapshot){ // 错误处理 if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } // 加载中处理 if (!snapshot.hasData) { return const Center(child: CircularProgressIndicator()); } // 数据加载完成渲染 List<Coordonnees> mark = snapshot.data!; return Center( child: Text( 'latitude: ${mark[0].latitude}', style: const TextStyle(fontSize: 30), ), ); }, ), ); } Future<List<Coordonnees>> UpdateMarkers(String id) async{ Map data = { 'idligne': id, }; final response = await http.post( Uri.parse("https://www.sirius-iot.eu/Dev/ESI/qitari2021/sarah.php?lignegps"), body: data ); Map<String,dynamic> map = json.decode(response.body); List<dynamic> dataa = map['lignegps']; List<Coordonnees> marqueurs = []; for(var i in dataa) { Coordonnees crd = Coordonnees( double.parse(i['latitude']), double.parse(i['longitude']), double.parse(i['vitesse']) ); marqueurs.add(crd); } return marqueurs; } Stream<List<Coordonnees>> get listMarkers async*{ String id = '1'; // 循环拉取接口,间隔5秒,可根据需求调整间隔时长 while (true) { yield await UpdateMarkers(id); await Future.delayed(const Duration(seconds: 5)); } } } class Coordonnees{ double latitude; double longitude; double vitesse; Coordonnees(this.latitude,this.longitude,this.vitesse); }
可选优化(推荐)
上述代码的无限循环Stream无法手动停止,页面销毁后仍会在后台发起请求,建议改用StreamController+Timer实现,在页面销毁时主动释放资源:
class _MyHomePageState extends State<MyHomePage> { final _markerController = StreamController<List<Coordonnees>>(); Timer? _pullTimer; @override void initState() { super.initState(); // 立即拉取首次数据 _pullData(); // 每隔5秒拉取一次数据 _pullTimer = Timer.periodic(const Duration(seconds: 5), (timer) => _pullData()); } Future<void> _pullData() async { try { final data = await UpdateMarkers('1'); _markerController.add(data); } catch (e) { _markerController.addError(e); } } @override void dispose() { _pullTimer?.cancel(); _markerController.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder( stream: _markerController.stream, builder: (BuildContext context,AsyncSnapshot<List<Coordonnees>> snapshot){ // 此处复用之前的builder逻辑即可 }, ), ); } // 其余方法保持不变 }
内容的提问来源于stack exchange,提问作者marie_12
相关产品推荐
相关产品推荐

