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
问题原因
- 未初始化错误:
_createdDiariesInThePast30Days用late修饰,但initState中调用的setVariables是异步方法,组件首次build时该变量还未完成赋值,直接调用toString()触发LateInitializationError。 - 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
相关产品推荐
相关产品推荐

