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

Flutter嵌套FutureBuilder引发无限循环:原因解析与修复方案

Flutter页面无限循环的原因与修复方案

问题原因

  • FutureBuilder的future参数在build中动态创建:你在内部FutureBuilder的future字段里直接执行了() { ... return APIService.Get_Old_Model_No(id); }(),每次页面build(比如计时器触发setState、输入框onChanged触发setState)时,都会重新创建并执行这个Future,发起新的API请求。
  • 计时器持续触发setState:启动计时器后,Timer.periodic每秒调用setState更新时间,导致页面频繁重建,进而反复触发内部API请求,形成无限循环。

修复步骤

1. 缓存内部API请求的Future,避免每次build重复执行

在State类中添加一个Map来缓存每个id对应的Future,避免重复发起请求:

class _ScreenState extends State<Screen> {
  // ... 原有变量保留
  Map<int, Future<Get_Old_Model_No>> _oldModelFutures = {}; // 用于缓存Future的Map

  // 初始化指定id对应的API请求Future
  void _initOldModelFuture(int id) {
    if (!_oldModelFutures.containsKey(id)) {
      _oldModelFutures[id] = APIService.Get_Old_Model_No(id);
    }
  }
}

2. 修改内部FutureBuilder的future参数

不再在build方法中动态创建Future,而是使用提前缓存的Future实例:

// 替换内部的FutureBuilder代码
Expanded(
  child: FutureBuilder<Get_Old_Model_No>(
    future: _oldModelFutures[id], // 使用缓存的Future
    builder: (context, snapshot) {
      print("Snapshot data:${snapshot.data}");
      print("Snapshot error:${snapshot.error}");
      if (snapshot.hasData) {
        return Column(
          children: [
            // Text(snapshot.data?.endDate),
          ],
        );
      } else if (snapshot.hasError) {
        return Text("${snapshot.error}");
      }
      return CircularProgressIndicator();
    },
  ),
)

同时在外部FutureBuilder获取到数据后,提前初始化对应id的Future:

// 在外部FutureBuilder的snapshot.hasData分支中添加初始化逻辑
return Column(
  children: List.generate(snapshot.data!.length, (int index) {
    final model = snapshot.data![index];
    // 替换为你实际获取id的逻辑(从model或路由参数中)
    final int id = ModalRoute.of(context)!.settings.arguments as Map<String,dynamic>['id'] ?? 0;
    _initOldModelFuture(id); // 提前缓存该id的API请求Future
    String Some_VariableName = model.name;
    return Column(
      children: [
        Text(model.name),
        // ... 后续原有代码
      ],
    );
  }),
);

3. 完善计时器的停止逻辑

确保点击停止按钮时能正确取消Timer,避免不必要的setState触发:

void _stopStopwatch() {
  _stopwatch.stop();
  _timer.cancel();
  setState(() {
    isStartButtonDisabled = false;
    isStopButtonDisabled = true;
  });
}

4. 优化输入框的状态更新逻辑

当前输入框onChanged每次输入都会触发setState,可以改用TextEditingController减少不必要的页面重建:

class _ScreenState extends State<Screen> {
  // ... 原有变量保留
  final TextEditingController _numberController = TextEditingController();

  @override
  void initState() {
    super.initState();
    // 通过监听控制器更新变量
    _numberController.addListener(() {
      final int? parsedValue = int.tryParse(_numberController.text);
      if (parsedValue != null) {
        setState(() {
          variable1 = parsedValue;
        });
      }
    });
  }

  @override
  void dispose() {
    _numberController.dispose(); // 销毁控制器
    super.dispose();
  }
}

然后替换原有的TextFormField:

TextFormField(
  controller: _numberController,
  keyboardType: TextInputType.number,
),

内容的提问来源于stack exchange,提问作者A_K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:01:19