Flutter中App启动时解析加载JSON文件的异步问题及解决
问题分析与解决方案
问题所在
readJson()是异步方法(返回Future<void>),你调用它时没有使用await关键字,导致代码不会等待异步操作完成就直接执行后续的print(myNotes.notes)。这时候JSON文件还没加载、解码完成,_notes还是初始的空Map,所以打印结果为空。
你的理解误区
你误以为调用异步方法会同步等待它执行完毕,但Dart的异步机制是:调用异步方法后会立即返回一个Future对象,代码继续向下执行;只有通过await或者监听Future的完成状态,才能确保在异步操作结束后再处理结果。另外,build()方法本身是同步执行的,不能直接在build()里使用await(因为build()不能被标记为async)。
代码修正方案
方案1:使用StatefulWidget的initState初始化加载
适合需要在页面初始化时加载数据,并手动管理加载状态的场景:
import 'package:flutter/services.dart' show rootBundle; import 'dart:convert'; class Notes { Map _notes = {}; Map get notes => _notes; Future<void> readJson() async { final String response = await rootBundle.loadString('assets/sample.json'); final data = json.decode(response); // json.decode本身不是异步方法,无需await _notes = data; } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late Notes myNotes; bool _isLoading = true; @override void initState() { super.initState(); myNotes = Notes(); _loadNotes(); } Future<void> _loadNotes() async { await myNotes.readJson(); // 更新状态触发重建,此时数据已加载完成 setState(() { _isLoading = false; }); print(myNotes.notes); // 这里能输出正确的JSON内容 } @override Widget build(BuildContext context) { if (_isLoading) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( body: Center( child: Text(myNotes.notes.toString()), ), ); } }
方案2:使用FutureBuilder处理异步状态
更简洁的方式,无需手动管理加载状态,适合直接依赖异步数据渲染UI的场景:
import 'package:flutter/services.dart' show rootBundle; import 'dart:convert'; class Notes { Map _notes = {}; Map get notes => _notes; Future<void> readJson() async { final String response = await rootBundle.loadString('assets/sample.json'); final data = json.decode(response); _notes = data; } } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); Future<Notes> _loadNotes() async { final notes = Notes(); await notes.readJson(); return notes; } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<Notes>( future: _loadNotes(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } else { final myNotes = snapshot.data!; print(myNotes.notes); // 这里能输出正确的JSON内容 return Center( child: Text(myNotes.notes.toString()), ); } }, ), ); } }
后续扩展说明
如果后续要加载非本地文件(比如网络接口),只需修改readJson()方法的实现,替换成网络请求逻辑即可,外部的状态管理和UI渲染逻辑无需大幅改动,保持异步方法的封装性即可。
内容的提问来源于stack exchange,提问作者Al C
相关产品推荐
相关产品推荐

