Flutter/Dart中如何在后台每5分钟调用API且不阻塞其他请求?
解决Timer定期调用API阻塞其他请求的问题
我尝试使用Timer实现每2分钟调用一次API,但该操作会阻塞其他API请求。以下是我的实现代码:
class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with WidgetsBindingObserver { int _timerCounter = 0; Timer? _timer; @override void initState() { try { super.initState(); WidgetsBinding.instance?.addObserver(this); _timer = Timer.periodic( const Duration(milliseconds: 120000), // 2分钟 _incrementTimerCounter ); } catch (error, s) { Functions.recordError(error, s); } }
初始化时设置Timer,并且在应用恢复状态时重新设置Timer:
@override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { _timer = Timer.periodic( const Duration(milliseconds: 120000), _incrementTimerCounter ); } else if (state == AppLifecycleState.paused) { _timer!.cancel(); } } void _incrementTimerCounter(Timer t) { if (!mounted) return; print("_timerCounter is $_timerCounter"); refereshData(); _timerCounter++; } Future refereshData() async { if (!mounted) return; if (await Utils.checkConnection()) { var data = Provider.of<ProviderPostData>(context, listen: false); await data.postDataCall(context); } } @override Widget build(BuildContext context) { return Container(); } }
问题原因
Timer的回调函数_incrementTimerCounter运行在主线程中,当refereshData里的postDataCall是耗时操作(比如同步网络请求、大量计算)时,会阻塞主线程,导致其他API请求、UI渲染等操作无法正常执行。
解决方案
1. 将耗时API调用移至后台隔离
使用Dart的compute函数把耗时操作放到独立的Isolate中执行,避免占用主线程:
import 'dart:async'; Future refereshData() async { if (!mounted) return; if (await Utils.checkConnection()) { var data = Provider.of<ProviderPostData>(context, listen: false); // 用compute将postDataCall移至后台执行 await compute((ProviderPostData targetData) async { await targetData.postDataCall(context); }, data); } }
2. 让异步操作独立执行,不阻塞Timer回调
使用unawaited忽略异步操作的结果,让它在后台独立运行,不阻塞当前线程的后续操作:
import 'dart:async'; void _incrementTimerCounter(Timer t) { if (!mounted) return; print("_timerCounter is $_timerCounter"); // 不等待refereshData完成,直接后台执行 unawaited(refereshData()); _timerCounter++; }
3. 避免重复创建Timer
当前代码在resumed状态下会直接创建新Timer,可能导致多个Timer同时运行,优化这部分逻辑:
@override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { // 仅当Timer不存在或未激活时创建新实例 if (_timer == null || !_timer!.isActive) { _timer = Timer.periodic( const Duration(minutes: 2), _incrementTimerCounter ); } } else if (state == AppLifecycleState.paused) { _timer?.cancel(); _timer = null; // 置空避免后续判断出错 } }
4. 确保postDataCall内部是真正的异步操作
检查postDataCall的实现,确保网络请求使用异步方法(比如http包的get/post本身是异步的),如果有同步耗时计算,同样需要移至Isolate处理。
内容的提问来源于stack exchange,提问作者Vanjara Sweta
相关产品推荐
相关产品推荐

