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

Flutter StreamBuilder报Infinity or NaN toInt错误如何解决

问题现象

构建StreamBuilder时抛出如下错误:

UnsupportedError: Unsupported operation: Infinity or NaN toInt
组件状态信息:组件为dirty状态,依赖项包括[_LocalizationsScope-[GlobalKey#7d7fa], _InheritedTheme],关联状态为_StreamBuilderBaseState<bool, AsyncSnapshot>#75e11
报错场景为:使用StreamBuilder监听加载状态,结合GridView.count实现日历类网格布局。

根因排查

这个错误的本质是组件渲染链路中出现了NaN(非数字)或Infinity(无穷大)的值,该值被传入需要整数类型的布局/绘制逻辑时触发类型转换失败,结合提供的代码,问题点集中在以下位置:

  • 核心问题出在Color.lerp的第三个插值参数计算逻辑:controller.countHabitsDone(day) / day.habits.length
    • 当day.habits.length为0(即当天没有绑定任何习惯)时,除以0的运算会直接得到NaN值
    • 若countHabitsDone(day)返回值为null、或返回值远超day.habits.length,也会导致插值参数非法
  • Color.lerp拿到NaN的插值参数后,会计算出非法的颜色通道值,后续GridView布局、绘制阶段做整数转换时就会抛出该错误,错误栈会定位到上层的StreamBuilder构建节点,容易误导排查方向
  • 额外边界风险:代码中直接使用snapshot.data!强制解包,若流发射异常值、初始值与实际流类型不匹配,也可能触发空值导致的非法运算
修复方案

针对上述问题点,逐处增加边界兜底逻辑即可:

  1. 做除法运算前先判断分母是否为0,避免除零产生NaN
  2. 对插值比例做范围限制,强制约束在0.0~1.0的合法区间内
  3. 对快照数据、业务数据增加空值兜底,避免强制解包带来的风险

修正后的核心代码片段如下:

StreamBuilder<bool>(
  stream: controller.loading.stream,
  initialData: controller.loading.value,
  builder: (context, snapshot) {
    // 增加加载状态兜底,流未就绪时优先展示加载态
    final isLoading = snapshot.data ?? true;
    return GridView.count(
      crossAxisCount: 7,
      mainAxisSpacing: 5,
      crossAxisSpacing: 5,
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      padding: const EdgeInsets.all(10),
      children: List.generate(days, (index) {
        if (index < whiteSpaces) {
          return const SizedBox.shrink();
        }

        final day = !isLoading
            ? controller.getDay(
                DateTime(year, month, index - whiteSpaces + 1))
            : null;

        // 提前计算颜色插值比例,全链路兜底
        Color bgColor = Theme.of(context).shadowColor;
        if (day != null && day.habits.isNotEmpty) {
          final doneCount = controller.countHabitsDone(day);
          // 计算比例后强制限制在0-1区间,避免非法值
          final ratio = (doneCount / day.habits.length).clamp(0.0, 1.0);
          bgColor = Color.lerp(
            Theme.of(context).shadowColor,
            Theme.of(context).primaryColor,
            ratio,
          )!;
        }

        return AnimatedContainer(
          duration: const Duration(milliseconds: 500),
          decoration: BoxDecoration(
            color: bgColor,
            borderRadius: BorderRadius.circular(5),
          ),
        );
      }),
    );
  },
)
排查延伸

如果修复后仍出现同类错误,可按以下顺序排查其他可能产生NaN/Infinity的位置:

  • 检查days、whiteSpaces变量的计算逻辑,是否存在除零、未初始化导致的非法值
  • 检查GridView是否被嵌套在横向/竖向无边界约束的父组件中,导致布局计算出无穷大尺寸
  • 检查AnimatedContainer是否存在动画起始/结束值设置为非法数值的情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:03:19