Flutter从SharedPreferences获取数据后如何刷新页面UI元素?
问题原因
你的代码存在3个核心问题导致UI无法在应用切回时自动更新:
_WeatherAppState没有混入WidgetsBindingObserver接口,应用生命周期状态变更的监听根本不会生效getData()是异步函数,你直接在setState()中调用它时,setState执行完成后异步拉取数据的逻辑才会执行,全局列表更新后没有再次触发UI重绘- 你使用全局列表存储数据,子组件没有监听该列表的变更,就算列表内容更新,子组件也不知道需要刷新自身UI
修复步骤
1. 补全生命周期监听的混入
修改 _WeatherAppState 类的定义,混入生命周期监听接口:
class _WeatherAppState extends State<WeatherApp> with WidgetsBindingObserver { // 保留你原有类内的所有代码即可 }
2. 改造异步逻辑调用顺序
首先修改 PreferencesService 中的 getData 方法,让它返回 Future 方便等待执行完成:
// 修改方法返回值为Future<void> Future<void> getData() async{ final preferences = await SharedPreferences.getInstance(); var jsonData = preferences.getString("weather_data"); if (jsonData == null){ locationList = []; } else{ locationList.clear(); var dataList = json.decode(jsonData); for (var e in dataList) { locationList.add( WeatherModel( weatherId: e["weatherId"], cityId: e["cityId"], city: e["city"], dateTime: e["dateTime"], temperature: e["temperature"], weatherType: e["weatherType"], iconUrl: e["iconUrl"], wind: e["wind"], rain: e["rain"], humidity: e["humidity"], ) ); } } }
再修改生命周期回调的逻辑,等数据拉取完成后再触发状态更新:
@override void didChangeAppLifecycleState(AppLifecycleState state) async { print('state = $state'); if (state == AppLifecycleState.resumed){ // 等待SharedPreferences数据拉取完成 await preferenceService.getData(); // 确认当前页面未销毁后触发UI重绘 if(mounted) setState(() {}); } }
3. 让子组件自动响应列表变更(可选,更稳定)
如果执行完前两步子组件依然没有更新,说明全局列表的变更没有触发子组件的重绘,用 ValueNotifier 改造全局列表即可:
首先修改全局 locationList 的定义:
// 替换你原来的locationList定义 ValueNotifier<List<WeatherModel>> locationList = ValueNotifier([]);
同步修改 getData 方法中操作列表的逻辑:
Future<void> getData() async{ final preferences = await SharedPreferences.getInstance(); var jsonData = preferences.getString("weather_data"); if (jsonData == null){ locationList.value = []; } else{ List<WeatherModel> newList = []; var dataList = json.decode(jsonData); for (var e in dataList) { newList.add( WeatherModel( weatherId: e["weatherId"], cityId: e["cityId"], city: e["city"], dateTime: e["dateTime"], temperature: e["temperature"], weatherType: e["weatherType"], iconUrl: e["iconUrl"], wind: e["wind"], rain: e["rain"], humidity: e["humidity"], ) ); } locationList.value = newList; } }
最后用 ValueListenableBuilder 包裹你原有子组件的UI代码,自动监听列表变更刷新:
ValueListenableBuilder<List<WeatherModel>>( valueListenable: locationList, builder: (context, list, child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(list.isNotEmpty ? list[widget.index].temperature : "--℃"), Row( children: [ SvgPicture.asset(list.isNotEmpty ? list[widget.index].iconUrl : "assets/rain.svg", width: 30,height: 30,color: Colors.white,), Text(list.isNotEmpty ? list[widget.index].weatherType : "Rainy",style: GoogleFonts.openSans(fontSize: 20,fontWeight: FontWeight.bold,color: Colors.white)), ], ), ], ); } )
内容的提问来源于stack exchange,提问作者Atharv Sharma
相关产品推荐
相关产品推荐

