Flutter中API返回JSON解析时变量偶现不更新问题求助
Flutter 网络请求偶发显示初始值问题修复
问题根因
你的判断完全准确,问题本质是异步逻辑的竞态,具体有三个触发点:
CanteenInfo的构造函数是同步执行的,内部调用的getWebsiteData()是异步方法,构造函数不会等待网络请求返回就完成初始化,此时workingHours还是初始值yes。如果网络请求速度快,在页面首次渲染前刚好完成赋值,就会显示正确值;如果请求稍慢,页面渲染时拿到的就是初始值。- 代码中调用的
canteen.getHours()方法并未在CanteenInfo类中定义,属于无效调用,根本没有触发数据读取的逻辑。 - 你直接在
build方法中调用包含setState的getHours()方法,build会在页面重绘时高频执行,会导致重复触发状态更新、无限重绘的额外问题。
修复方案
核心是把异步逻辑的状态显式管理起来,不要依赖“请求刚好在渲染前完成”的概率,分两步修改:
- 重构
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'); } }
- 重构页面状态逻辑,用官方提供的
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
相关产品推荐
相关产品推荐

