Flutter(Getx)异步Future执行顺序控制及视图不更新问题排查
问题描述
我正在使用Getx库开发Flutter项目,由于项目交付日期临近,无法修改后端,只能基于现有后端响应在前端重组为UI模型并展示。
我需要保证两个异步Future的执行顺序:先获取Survey结果列表并提取其中的Survey ID存入列表,再获取Survey列表,通过对比ID列表判断每个Survey是否已完成。我原本以为使用await可以保证执行顺序,但视图并未发生任何变化。
相关代码
Controller代码
class ExampleController extends GetxController { final PreferenceManager _preferenceManager = Get.find(tag: (PreferenceManager).toString()); /// ------------> related to survey values final RxList<SurveyListUiModel> _rxSurveyListUiModelList = RxList.empty(); List<SurveyListUiModel> get surveyListUiModelList = _rxSurveyListUiModelList.toList(); final List<String> _surveyResultIdList = []; void getSurveyConfigListWithSurveyResult() async{ Future<String> surveyResultListFuture = _preferenceManager.getString('survey_result_list'); callDataService( surveyResultListFuture, onSuccess: _handleSurveyResultListResponseSuccess, ); Future<String> surveyListFuture = _preferenceManager.getString('survey_list'); await callDataService( surveyConfigListFuture, onSuccess: _handleSurveyListResponseSuccess, ); setListLoading(false); } void _handleSurveyResultListResponseSuccess(String response) { List<dynamic> list = jsonDecode(response) as List<dynamic>; for (var element in list) { SurveyConfigResponse surveyConfigResponse = SurveyConfigResponse.fromJson( element['survey_config'] as Map<String, dynamic>); _surveyResultIdList.add(surveyConfigResponse.id); } } void _handleSurveyListResponseSuccess(String response) { List<dynamic> list = jsonDecode(response) as List<dynamic>; for (var element in list) { SurveyConfigResponse surveyConfigResponse = SurveyConfigResponse.fromJson(element as Map<String, dynamic>); surveyListUiModelList.add(SurveyListUiModel( surveyConfigId: surveyConfigResponse.id, surveyConfigTitle: surveyConfigResponse.title, isDiagnosed: _surveyResultIdList.contains(surveyConfigResponse.id), )); _rxSurveyListUiModelList.refresh(); } } /// ------------> related to survey values @override void onInit() { getSurveyConfigListWithSurveyResult(); super.onInit(); } }
callDataService方法
dynamic callDataService<T>( Future<T> future, { Function(Exception exception)? onError, Function(T response)? onSuccess, Function? onStart, Function? onComplete, }) async { Exception? _exception; onStart == null ? showLoading() : onStart(); try { final T response = await future; if (onSuccess != null) onSuccess(response); onComplete == null ? hideLoading() : onComplete(); return response; } on ServiceUnavailableException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on UnauthorizedException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on TimeoutException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on NetworkException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on JsonFormatException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on NotFoundException catch (exception) { _exception = exception; showErrorMessage(exception.message); } on ApiException catch (exception) { _exception = exception; } on AppException catch (exception) { _exception = exception; showErrorMessage(exception.message); } catch (error) { _exception = AppException(message: "$error"); logger.e("Controller>>>>>>> error $error"); } if (onError != null) onError(_exception); onComplete == null ? hideLoading() : onComplete(); }
视图代码
class ExampleView extends GetView<ExampleController> { @override Widget body(BuildContext context) { return Obx(() => Text(controller.surveyListUiModelList.length.toString())); } }
已确认回调方法中的列表值是正确的,但视图仍无更新,请问我的代码中遗漏了什么?
问题分析与修复方案
核心问题点
- 异步执行顺序未保证:第一个
callDataService调用未加await,导致两个异步请求并行执行,_surveyResultIdList还未填充完成就开始处理Survey列表,不仅判断逻辑错误,还会导致UI更新混乱。 - Getter语法错误:
surveyListUiModelList的getter使用=而非=>,这会导致该列表仅在初始化时获取一次_rxSurveyListUiModelList的副本,后续RxList更新时,getter返回的始终是旧数据,Obx无法感知变化。 - 操作错误的列表:在
_handleSurveyListResponseSuccess中,往RxList的副本surveyListUiModelList添加元素,而非直接操作_rxSurveyListUiModelList,导致RxList未实际更新,手动调用refresh()也无法触发UI刷新。 - 变量名错误:第二个
callDataService传入的surveyConfigListFuture未定义,实际应为surveyListFuture。
修复后的Controller代码
class ExampleController extends GetxController { final PreferenceManager _preferenceManager = Get.find(tag: (PreferenceManager).toString()); /// ------------> related to survey values final RxList<SurveyListUiModel> _rxSurveyListUiModelList = RxList.empty(); // 修复Getter写法,每次调用返回最新的RxList副本 List<SurveyListUiModel> get surveyListUiModelList => _rxSurveyListUiModelList.toList(); final List<String> _surveyResultIdList = []; void getSurveyConfigListWithSurveyResult() async { Future<String> surveyResultListFuture = _preferenceManager.getString('survey_result_list'); // 添加await保证第一个请求执行完成后再执行第二个 await callDataService( surveyResultListFuture, onSuccess: _handleSurveyResultListResponseSuccess, ); Future<String> surveyListFuture = _preferenceManager.getString('survey_list'); // 修复变量名错误 await callDataService( surveyListFuture, onSuccess: _handleSurveyListResponseSuccess, ); setListLoading(false); } void _handleSurveyResultListResponseSuccess(String response) { List<dynamic> list = jsonDecode(response) as List<dynamic>; for (var element in list) { SurveyConfigResponse surveyConfigResponse = SurveyConfigResponse.fromJson( element['survey_config'] as Map<String, dynamic>); _surveyResultIdList.add(surveyConfigResponse.id); } } void _handleSurveyListResponseSuccess(String response) { List<dynamic> list = jsonDecode(response) as List<dynamic>; // 直接操作RxList,自动触发响应式更新 for (var element in list) { SurveyConfigResponse surveyConfigResponse = SurveyConfigResponse.fromJson(element as Map<String, dynamic>); _rxSurveyListUiModelList.add(SurveyListUiModel( surveyConfigId: surveyConfigResponse.id, surveyConfigTitle: surveyConfigResponse.title, isDiagnosed: _surveyResultIdList.contains(surveyConfigResponse.id), )); } // RxList添加元素后自动通知更新,无需手动调用refresh() } /// ------------> related to survey values @override void onInit() { getSurveyConfigListWithSurveyResult(); super.onInit(); } }
说明
- 修复后两个异步请求会按顺序执行,
_surveyResultIdList填充完成后再处理Survey列表,保证isDiagnosed判断正确。 - 直接操作RxList会自动触发Getx的响应式更新,Obx能感知到
surveyListUiModelList的变化并刷新视图。
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

