Flutter pop返回后获取城市天气数据但UI未更新问题
问题根源
你的UI不更新核心是两个代码逻辑错误,附带一个边界崩溃隐患:
- 最主要问题:
setState方法的回调不支持async异步操作。你把网络请求写在setState内部,Flutter执行到setState时不会等待await的网络请求返回,会直接触发UI重建,等网络数据真正拿到的时候,本次刷新流程已经结束,自然不会把新数据渲染到界面上。 - 第二个问题:
updateUI方法的空判断逻辑不完整。当weatherData为null时,你只给三个变量赋了默认值,没有中断执行,后续代码会直接尝试从null上取下标属性,直接抛运行时异常,中断更新流程。 - 边界隐患:城市选择页的
cityName用late修饰,如果用户进入页面后没有输入内容直接返回,会触发late变量未初始化的崩溃。
修复方案
1. 修正按钮点击逻辑,把异步请求移到setState外部
先等待网络请求拿到完整数据,再调用setState更新状态:
FlatButton( onPressed: () async { dynamic typedname = await Navigator.push( context, MaterialPageRoute( builder: (context) => Cityscreen())); // 用户直接返回未输入城市时终止流程 if (typedname == null || typedname.isEmpty) return; // 先等网络请求返回数据 dynamic weatherData = await weatherModel.getCityLocation(typedname); // 数据就绪后再触发UI更新 setState(() { updateUI(weatherData); }); }, )
2. 补全updateUI的空判断逻辑
空数据场景下赋值完默认值直接return,避免后续执行空对象取值操作:
void updateUI(var weatherData) { if (weatherData == null) { city = ''; temperature = 0; weatherMessage = 'Unable to fetch data'; weatherIcon = null; description = ''; // 终止后续执行 return; } id = weatherData['weather'][0]['id']; weatherIcon = weatherModel.getWeatherIcon(id); city = weatherData['name']; double temp = weatherData['main']['temp']; temperature = temp.toInt(); weatherMessage = weatherModel.getMessage(temperature); description = weatherData['weather'][0]['description']; }
3. 修复城市选择页的变量初始化问题
给cityName设置空字符串默认值,去掉late修饰,避免未初始化崩溃:
class _CityscreenState extends State<Cityscreen> { // 给默认初始值,不需要late修饰 String cityName = ''; @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('images/back1.jpg'), fit: BoxFit.fill, ), ), constraints: BoxConstraints.expand(), child: SafeArea( child: Column( children: [ Align( alignment: Alignment.topLeft, child: FlatButton( onPressed: () { Navigator.pop(context); }, child: Icon( Icons.arrow_back_ios, size: 50.0, ), ), ), Container( padding: EdgeInsets.all(20.0), child: TextField( style: TextStyle( color: Colors.black, ), decoration: kTextFieldDecoration, onChanged: (value) { cityName=value; }, ), ), FlatButton( onPressed: (){ Navigator.pop(context,cityName); }, child: Text( 'Get weather', style: TextStyle( fontSize: 30, ), ), color: Colors.deepPurpleAccent, ), ], ), ), ), // 补全原有剩余代码即可 ); } }
改完之后网络请求返回的数据就可以正常触发UI刷新了。
内容的提问来源于stack exchange,提问作者Hamza Khan
相关产品推荐
相关产品推荐

