Flutter页面初始化仅调用一次API并显示加载进度的解决方案
解决方案:页面首次加载仅调用一次异步接口并显示加载状态
要实现页面初始化时仅调用一次getVerificationMethods,且等待期间显示加载进度,同时避免页面重建重复执行,可通过State生命周期+ViewModel初始化标记解决,具体修改如下:
1. 页面State层修改
利用initState仅在页面首次创建时执行一次的特性,结合ViewModel的initLoaded标记控制初始化逻辑:
class _VerificationMethodScreenState extends State<VerificationMethodScreen> { late VerificationMethodViewModel _viewModel; @override void initState() { super.initState(); // initState中用read获取ViewModel,避免watch带来的状态监听问题 _viewModel = context.read<VerificationMethodViewModel>(); // 仅在未初始化时执行异步调用 if (!_viewModel.initLoaded) { _viewModel.onInit(); } } @override Widget build(BuildContext context) { // build中用watch监听ViewModel状态变化,更新UI _viewModel = context.watch<VerificationMethodViewModel>(); return init(context); } // 原init方法保持不变 Widget init(BuildContext context) { return Stack( children: [ Scaffold( appBar: CommonAppBar(context: context), body: _viewModel.loading ? const CircularProgressIndicator() : Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Center( child: LocaleText( 'select_verification_method', textAlign: TextAlign.center, style: ThemeHelper().titleText(fontSize: 22.0), ), ), GestureDetector( onTap: () => _viewModel.performVerification( method: VerificationMethods.mobileId), child: CommonVerificationButton( context: context, title: 'Mobile ID', icon: Icons.phone_android_outlined)), GestureDetector( onTap: () => _viewModel.performVerification( method: VerificationMethods.mrz), child: CommonVerificationButton( context: context, title: 'MRZ', icon: Icons.document_scanner_outlined), ), GestureDetector( onTap: () => _viewModel.performVerification( method: VerificationMethods.ocr), child: CommonVerificationButton( context: context, title: 'OCR', icon: Icons.qr_code_scanner_outlined), ), ], ), ), CommonProgressIndicator( context: context, showDialog: _viewModel.loading, ) ], ); } }
2. ViewModel层修改
完善onInit方法,添加初始化完成标记,防止ViewModel重建时重复执行异步接口:
class VerificationMethodViewModel extends BaseViewModel { Future<void> onInit() async{ // 双重检查,避免并发场景下重复调用 if (!initLoaded) { setInitLoaded(true); // 先标记为已初始化,防止重复触发 await getVerificationMethods(); } } // 原performVerification、getVerificationMethods方法保持不变 Future<bool> performVerification({required VerificationMethods method}) async { bool canPerform = false; setLoading(true); try { await Future.delayed(const Duration(seconds: 1)); canPerform = true; } catch (e) { errorMessage = "Internal error occurred!"; } finally { setLoading(false); } return canPerform; } Future<List<VerificationMethodsModel>> getVerificationMethods() async { setLoading(true); final items = <VerificationMethodsModel>[ VerificationMethodsModel(1, null, "Mobile ID", "Mobile ID", null, "mobile_id", 1, List.empty()), VerificationMethodsModel( 2, null, "MRZ", "MRZ", null, "mrz", 2, List.empty()), VerificationMethodsModel( 3, null, "OCR", "OCR", null, "OCR", 3, <VerificationMethodsModel>[ VerificationMethodsModel(4, 3, "Civil ID", "البطاقة المدنية", "Civil ID", "Kuwait_ID", 1, List.empty()), VerificationMethodsModel(5, 3, "Non Kuwaity ID", "Non Kuwaity ID", "Civil ID", "NonKuwait_ID", 2, List.empty()), VerificationMethodsModel( 6, 3, "KSA ID", "KSA ID", "Civil ID", "SAU_ID", 3, List.empty()), ], ), ]; try { await Future.delayed(const Duration(seconds: 2)); } catch (e) { errorMessage = "Internal error occurred!"; } finally { setLoading(false); } return items; } }
核心逻辑说明
initState是StatefulWidget页面首次创建时唯一执行的生命周期方法,保证初始化逻辑仅触发一次。- ViewModel中的
initLoaded标记,进一步规避因配置变更(如语言、主题切换)导致ViewModel重建时重复调用接口的问题。 - 原加载状态控制逻辑无需修改,
getVerificationMethods中通过setLoading维护的状态可正确在异步操作期间显示加载进度。
内容的提问来源于stack exchange,提问作者abhi
相关产品推荐
相关产品推荐

