You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:57:03