如何通过Stream定期刷新Flutter数据?将Future请求改造为每5秒动态更新的实现方案
嘿,我来帮你把这个Future改成支持定时自动刷新的Stream,这样就能实现每5秒更新一次货币数据啦!咱们分几步来改:
第一步:改造数据获取逻辑,创建定时Stream
在你存放_fetchCurrency的文件里,新增一个返回Stream的方法,用它来包装你的异步请求,实现每5秒触发一次:
// 保留你原有的_fetchCurrency方法,这是实际拉取数据的核心逻辑 Future<List<CurrencyModel>?> _fetchCurrency() async { currencyList = []; final response = await http.get( Uri.parse('https:...'), // 你的API地址 ); if (response.statusCode == 200) { List<dynamic> values = json.decode(response.body); if (values.isNotEmpty) { for (int i = 0; i < values.length; i++) { if (values[i] != null) { Map<String, dynamic> map = values[i]; currencyList.add(CurrencyModel.fromJson(map)); } } } return currencyList; } else { throw Exception('Failed to load currencies'); } } // 新增:创建一个每隔5秒自动拉取数据的Stream Stream<List<CurrencyModel>?> getCurrencyStream() { // Stream.periodic会按指定间隔发送事件,我们忽略事件本身,每次调用_fetchCurrency return Stream.periodic(const Duration(seconds: 5), (_) => _fetchCurrency()) .asyncMap((future) => future); // 把Future转换成Stream的元素 }
第二步:修改主页面,用StreamBuilder替换FutureBuilder
在主页面的State类里,我们需要初始化Stream,然后把原来的FutureBuilder换成StreamBuilder:
class _YourPageState extends State<YourPage> { late Stream<List<CurrencyModel>?> _currencyStream; StreamSubscription? _streamSubscription; // 用来管理流的订阅,防止内存泄漏 @override void initState() { super.initState(); // 如果你想页面一打开就自动刷新,就初始化流;如果想通过按钮启动,就把这行移到startTimer里 // _currencyStream = client.getCurrencyStream(); // _streamSubscription = _currencyStream.listen((_) {}); } void startTimer() { setState(() { // 启动流(如果之前有订阅,先取消再重新订阅) _streamSubscription?.cancel(); _currencyStream = client.getCurrencyStream(); _streamSubscription = _currencyStream.listen((_) {}); }); } @override void dispose() { // 页面销毁时一定要取消订阅,避免内存泄漏 _streamSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Currencies'), centerTitle: true, ), body: StreamBuilder<List<CurrencyModel>?>( stream: _currencyStream, initialData: null, // 初始状态显示加载中 builder: (context, snapshot) { if (snapshot.hasData) { // 这里不要用全局的currencyList,直接用snapshot.data! return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) => CurrencyCard( snapshot.data![index], ), ); } else if (snapshot.hasError) { return Text('${snapshot.error}'); } return const Center(child: CircularProgressIndicator()); }, ), floatingActionButton: FloatingActionButton( onPressed: startTimer, child: const Icon(Icons.update_sharp), ), ); } }
几个关键注意点:
- 不要依赖全局的currencyList:尽量用
StreamBuilder的snapshot.data来获取最新数据,避免全局变量导致的数据不同步问题。 - 取消流订阅:在页面销毁时一定要调用
_streamSubscription?.cancel(),不然会造成内存泄漏。 - API频率限制:如果你的目标API有请求频率限制,要确认5秒一次的调用不会触发限流,必要时可以调整间隔时间。
这样改完之后,点击浮动按钮就能启动定时刷新,每5秒自动拉取最新的货币数据并更新UI啦!
内容的提问来源于stack exchange,提问作者userName
相关产品推荐
相关产品推荐

