You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:48:22