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

Flutter中GridView Builder内异步函数为何无限循环?

解决DynamicHeightGridView中异步函数触发无限重建的问题

问题根源

  1. 无限重建循环:DynamicHeightGridView的builder每次触发都会调用listOfSensors,而listOfSensors里直接执行compareWinder,该函数最后调用setState触发Widget重建。重建后builder会再次调用listOfSensors,重复执行异步请求和setState,形成无限循环。
  2. 全局状态污染:showWarning是全局变量,若后续列表项增多,会导致多个item的警告状态互相覆盖。
  3. Firebase请求逻辑冗余:getLastDoc中遍历sensors的条件存在错误(sensors[i]['name'] == widget.list应为匹配当前item的名称),且limitToLast(1)后仍遍历所有值,没必要。

解决方案

1. 用FutureBuilder替代直接调用setState

将异步数据获取和UI渲染逻辑封装到FutureBuilder中,避免在build流程中直接触发setState。

修改listOfSensors函数:

Widget listOfSensors(int index) {
  String name = widget.list[index][0];
  double setValue = double.parse(widget.list[index][2]);
  
  return FutureBuilder<double>(
    // 传入预初始化的future(后续优化点),避免每次build重新发起请求
    future: getLastDoc(index, name),
    initialData: 0.0,
    builder: (context, snapshot) {
      // 根据异步返回值直接判断警告状态
      bool showWarning = snapshot.hasData && snapshot.data! > setValue;
      
      return Container(
          decoration: BoxDecoration(
              color: const Color(0xFF393053),
              borderRadius: BorderRadius.circular(20)),
          child: Padding(
            padding: const EdgeInsets.all(10),
            child: GestureDetector(
              child: ListTile(
                  leading: showWarning
                      ? const Icon(
                          Icons.warning,
                          color: Colors.yellow,
                        )
                      : null,
                  title: Text(
                    widget.list[index][0],
                    style: TextStyle(
                        color: Colors.white, fontSize: mobile ? 15 : 20),
                  ),
                  subtitle: Text(
                    widget.list[index][1],
                    style: TextStyle(
                        color: Colors.white, fontSize: mobile ? 10 : 12),
                  ),
                  trailing: Icon(
                    Icons.launch_rounded,
                    color: Colors.white,
                    size: mobile ? 20 : 30,
                  )),
            ),
          ));
    },
  );
}

2. 优化Firebase数据获取逻辑

修正遍历条件,简化数据解析:

Future<double> getLastDoc(int index, String name) async {
  String location = "";
  double val = 0;
  // 修正匹配条件,对应当前列表项的名称
  for (String i in sensors.keys) {
    if (sensors[i]['name'] == widget.list[index][0]) {
      location = i;
      break;
    }
  }
  final ref = FirebaseDatabase.instance.ref('items/$location/$name');
  Query query = ref.limitToLast(1);
  final dataSnapshot = await query.once();
  if (dataSnapshot.snapshot.exists) {
    Map data = dataSnapshot.snapshot.value as Map;
    // limitToLast(1)只会返回一条数据,直接取第一个值即可
    var firstValue = data.values.first;
    EvapData json = EvapData.fromJson(firstValue);
    val = json.winder;
    print(val);
  }
  return val;
}

3. 避免重复发起异步请求

在initState中预初始化所有item的请求Future,防止每次build都重新发起Firebase请求:

List<Future<double>>? _sensorFutures;

@override
void initState() {
  super.initState();
  // 提前创建所有传感器的请求Future
  _sensorFutures = widget.list.map((item) {
    String name = item[0];
    int index = widget.list.indexOf(item);
    return getLastDoc(index, name);
  }).toList();
}

然后在listOfSensors中替换future参数:

future: _sensorFutures![index],

4. (可选)实时监听Firebase数据变化

若需要实时感知数据库更新,将once()改为onValue监听,无需手动刷新:

Stream<double> listenToLastDoc(int index, String name) async* {
  String location = "";
  for (String i in sensors.keys) {
    if (sensors[i]['name'] == widget.list[index][0]) {
      location = i;
      break;
    }
  }
  final ref = FirebaseDatabase.instance.ref('items/$location/$name');
  await for (final event in ref.limitToLast(1).onValue) {
    double val = 0;
    if (event.snapshot.exists) {
      Map data = event.snapshot.value as Map;
      var firstValue = data.values.first;
      EvapData json = EvapData.fromJson(firstValue);
      val = json.winder;
    }
    yield val;
  }
}

此时将FutureBuilder替换为StreamBuilder即可实现实时更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:17:48