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

Flutter中API返回JSON解析时变量偶现不更新问题求助

Flutter 网络请求偶发显示初始值问题修复

问题根因

你的判断完全准确,问题本质是异步逻辑的竞态,具体有三个触发点:

  • CanteenInfo的构造函数是同步执行的,内部调用的getWebsiteData()是异步方法,构造函数不会等待网络请求返回就完成初始化,此时workingHours还是初始值yes。如果网络请求速度快,在页面首次渲染前刚好完成赋值,就会显示正确值;如果请求稍慢,页面渲染时拿到的就是初始值。
  • 代码中调用的canteen.getHours()方法并未在CanteenInfo类中定义,属于无效调用,根本没有触发数据读取的逻辑。
  • 你直接在build方法中调用包含setState的getHours()方法,build会在页面重绘时高频执行,会导致重复触发状态更新、无限重绘的额外问题。

修复方案

核心是把异步逻辑的状态显式管理起来,不要依赖“请求刚好在渲染前完成”的概率,分两步修改:

  1. 重构CanteenInfo类,不要在构造函数里跑无等待的异步逻辑,把获取营业时间的逻辑封装成可被外部等待的异步方法:
import 'dart:convert';
import 'package:http/http.dart' as http;

class CanteenInfo {
  final String canteenUrl = 'https://sigarra.up.pt/feup/pt/mob_eme_geral.cantinas';

  Future<String> fetchWorkingHours() async {
    final response = await http.get(Uri.parse(canteenUrl));
    if (response.statusCode == 200) {
      final data = json.decode(response.body);
      return data[3]["horario"];
    }
    throw Exception('Failed to load canteen info');
  }
}
  1. 重构页面状态逻辑,用官方提供的FutureBuilder组件监听异步请求状态,初始化请求的逻辑放到只执行一次的initState生命周期中,分别处理加载、报错、成功三种展示状态,彻底避免拿到初始值的问题:
class WorkingHours extends StatefulWidget {
  const WorkingHours({Key? key}) : super(key: key);

  @override
  State<WorkingHours> createState() => _WorkingHours();
}

class _WorkingHours extends State<WorkingHours> {
  late Future<String> _workingHoursFuture;
  final CanteenInfo _canteen = CanteenInfo();

  @override
  void initState() {
    super.initState();
    // 页面初始化时仅触发一次网络请求,不要放到build方法里
    _workingHoursFuture = _canteen.fetchWorkingHours();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('EasyFood'),
      ),
      body: Center(
        child: Container(
          margin: const EdgeInsets.only(top: 100),
          child: FutureBuilder<String>(
            future: _workingHoursFuture,
            builder: (context, snapshot) {
              // 请求未完成时显示加载状态,不会再展示错误的初始值
              if (snapshot.connectionState != ConnectionState.done) {
                return const CircularProgressIndicator();
              }
              // 请求出错时展示错误提示
              if (snapshot.hasError) {
                return Text(
                  '获取营业时间失败',
                  style: const TextStyle(fontSize: 20, color: Colors.red),
                );
              }
              // 请求成功展示正确的营业时间
              return Text(
                'Lunch: ${snapshot.data}',
                style: const TextStyle(fontSize: 20),
              );
            },
          ),
        ),
      ),
    );
  }
}

注意事项

  • Dart 构造函数本身不支持异步,永远不要在构造函数里调用不加await的异步方法,否则外部完全无法感知异步任务的完成时机,必然出现竞态问题。
  • 不要在build方法中执行网络请求、调用setState这类会触发重绘的逻辑,build会在页面状态变化时高频执行,会导致重复请求、无限重绘的性能问题,初始化逻辑统一放到initState中。
  • 处理异步UI数据优先用FutureBuilder/StreamBuilder这类官方组件,它会自动跟踪异步任务的生命周期,不用手动写状态变量控制展示,逻辑更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:33:28