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

Flutter组件加载时无法显示API数据问题求助

Flutter组件加载时无法显示API返回数据,热重载后正常的问题解决

组件首次加载时无法显示Firebase获取的数据,报错LateInitializationError,但热重载后数据能正常显示。相关代码及报错信息如下:

父组件代码

class _ReportsState extends State<Reports> {
  late DiaryFirebaseCloudStorage _diaryRepository;
  late var _createdDiariesInThePast30Days;

  @override
  void initState() {
    super.initState();
    _diaryRepository = DiaryFirebaseCloudStorage();
    setVariables();
  }

  setVariables() async {
    _createdDiariesInThePast30Days =
        await _diaryRepository.getCreatedDiariesBasedOnPreviousDays(30);
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(kToolbarHeight),
          child: AppBarIconContainer(),
        ),
        body: Column(children: [
          Expanded(
              child: GridView.count(
                  crossAxisCount: 2, // Number of boxes per row
                  children: [
                SingleDigitReport(
                    number: _createdDiariesInThePast30Days.toString())
              ]))
        ]));
  }
}

Firebase数据获取类代码

class DiaryFirebaseCloudStorage {
  final _diary = FirebaseFirestore.instance.collection('diary');
  // final _user = FirebaseAuth.instance.currentUser!;
  final _user = AuthHandler.getUser();

  // Future<int>
  getCreatedDiariesBasedOnPreviousDays(days) async {
    print("getCreatedDiariesBasedOnPreviousDays()");
    final now = DateTime.now();
    final daysDelta = now.subtract(Duration(days: days));
    final querySnapshot = await _diary
        .where(createdByColumn, isEqualTo: _user.uid)
        .where(createdOnColumn, isGreaterThan: daysDelta)
        .get();
    return querySnapshot.docs.length;
  }

// singleton
  static final DiaryFirebaseCloudStorage _shared =
      DiaryFirebaseCloudStorage._sharedInstance();
  DiaryFirebaseCloudStorage._sharedInstance();
  factory DiaryFirebaseCloudStorage() => _shared;
}

报错信息

════════ Exception caught by widgets library ═══════════════════════════════════
The following LateError was thrown building Reports(dirty, state: _ReportsState#8004c):
LateInitializationError: Field '_createdDiariesInThePast30Days@561088100' has not been initialized.

The relevant error-causing widget was
Reports
hub.dart:70
When the exception was thrown, this was the stack
#0      _ReportsState._createdDiariesInThePast30Days (package:thraive/pages/reports/reports.dart)
reports.dart:1
#1      _ReportsState.build
reports.dart:46
#2      StatefulElement.build
framework.dart:5080
#3      ComponentElement.performRebuild
framework.dart:4968
#4      StatefulElement.performRebuild

问题原因

  1. 未初始化错误:_createdDiariesInThePast30Days用late修饰,但initState中调用的setVariables是异步方法,组件首次build时该变量还未完成赋值,直接调用toString()触发LateInitializationError。
  2. UI未自动刷新:异步获取数据后没有调用setState()通知框架更新UI,数据加载完成后界面不会自动刷新,只有热重载触发重新build时才会显示数据。

解决方案

方案一:使用FutureBuilder(推荐)

FutureBuilder是Flutter专门处理异步数据渲染的组件,能自动管理加载、成功、错误状态,无需手动调用setState:

class _ReportsState extends State<Reports> {
  late DiaryFirebaseCloudStorage _diaryRepository;
  // 将变量改为Future<int>类型,直接存储异步任务
  late Future<int> _createdDiariesInThePast30Days;

  @override
  void initState() {
    super.initState();
    _diaryRepository = DiaryFirebaseCloudStorage();
    // 直接初始化Future,无需单独异步方法
    _createdDiariesInThePast30Days = 
        _diaryRepository.getCreatedDiariesBasedOnPreviousDays(30);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(kToolbarHeight),
        child: AppBarIconContainer(),
      ),
      body: Column(children: [
        Expanded(
          child: FutureBuilder<int>(
            future: _createdDiariesInThePast30Days,
            builder: (context, snapshot) {
              // 加载中状态
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const Center(child: CircularProgressIndicator());
              }
              // 错误状态
              if (snapshot.hasError) {
                return Center(child: Text('加载失败: ${snapshot.error}'));
              }
              // 成功状态
              final count = snapshot.data ?? 0;
              return GridView.count(
                crossAxisCount: 2,
                children: [
                  SingleDigitReport(number: count.toString())
                ],
              );
            },
          ),
        ),
      ]),
    );
  }
}

方案二:手动管理状态并调用setState

如果不想用FutureBuilder,可修改变量声明并在数据加载完成后调用setState:

class _ReportsState extends State<Reports> {
  late DiaryFirebaseCloudStorage _diaryRepository;
  // 去掉late,给初始值0避免未初始化错误
  int _createdDiariesInThePast30Days = 0;

  @override
  void initState() {
    super.initState();
    _diaryRepository = DiaryFirebaseCloudStorage();
    setVariables();
  }

  setVariables() async {
    final count = await _diaryRepository.getCreatedDiariesBasedOnPreviousDays(30);
    // 调用setState更新UI
    setState(() {
      _createdDiariesInThePast30Days = count;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(kToolbarHeight),
        child: AppBarIconContainer(),
      ),
      body: Column(children: [
        Expanded(
          child: GridView.count(
            crossAxisCount: 2,
            children: [
              SingleDigitReport(
                number: _createdDiariesInThePast30Days.toString()
              )
            ],
          ),
        ),
      ]),
    );
  }
}

额外优化建议

给getCreatedDiariesBasedOnPreviousDays方法指定明确的返回类型,避免类型不确定:

Future<int> getCreatedDiariesBasedOnPreviousDays(int days) async {
  // 原有代码不变
}

内容的提问来源于stack exchange,提问作者user17281101

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:44:55