Flutter/Dart中async/await未等待异步操作完成导致数据初始化异常的解决方法
问题分析
你遇到的核心问题是异步操作的执行顺序错误:initState是同步方法,不能直接使用async/await,所以你在initState里调用getData()后立刻执行doSetup()时,getData()里的异步数据库查询还没完成,导致allSlokamsList还是空数组,进而_init()里的映射构建也失败了。
解决方案
我们需要确保getData()完成数据加载后,再执行依赖这些数据的doSetup()。可以通过封装一个异步初始化方法来实现:
修改后的代码示例
List<String> allSlokamIdsList = []; List<Slokam> allSlokamsList = []; Map<String, List<String>> allSlokamsMap = {}; List<String> sungSlokams = []; var knownSlokams = {'nma': <String>[], 'mpd': <String>[]}; late String currentAksharam; late String currentVrtham; var currentPlayerNo = 0; late String currentSlokam; @override void initState() { super.initState(); print('in sadas'); // 调用封装的异步初始化方法 _initializeApp(); } // 封装异步初始化逻辑,确保数据加载完成后再执行后续操作 Future<void> _initializeApp() async { await getData(); // 等待数据库查询完成,allSlokamsList被赋值 doSetup(); // 现在可以安全地执行依赖数据的操作 } @override void dispose() { player.dispose(); super.dispose(); } Future<void> getData() async { allSlokamsList = await dbHelper.getSlokams(); allSlokamIdsList = await dbHelper.getSlokamIds(); // print(allSlokamsList[1].first_line); } void doSetup() { _init(); _getAudioList(); player.playbackEventStream.listen((event) { if (event.processingState == ProcessingState.completed) { slokamCompleted(); } }); } void _init() { print('_init'); isPlaying = false; isPaused = false; isStopped = true; print('allSlokamsList = $allSlokamsList'); for (var item in allSlokamsList) { allSlokamsMap[item.slokam_id] = [ item.aksharam, item.aksharam3, item.slokam_text ]; } print('allSlokamsMap=$allSlokamsMap'); }
关键改动说明
- 新增
_initializeApp()异步方法:这个方法可以使用await等待getData()完成,确保allSlokamsList和allSlokamIdsList被正确赋值后,再调用doSetup()。 - 调整
initState()逻辑:不再直接调用getData()和doSetup(),而是调用封装的异步方法,避免同步方法里的异步操作顺序问题。 - 移除
doSetup()的async修饰符:因为现在它不需要等待异步操作,只需在数据准备好后同步执行即可。
预期打印结果
修改后,控制台输出顺序会变成:
I/flutter (17648): in sadas I/flutter (17648): _init I/flutter (17648): allSlokamsList = [Slokam实例1, Slokam实例2, ...] I/flutter (17648): allSlokamsMap={slokam_id_1: [aksharam值, aksharam3值, slokam_text值], ...}
额外建议
如果数据库查询耗时较长,建议在初始化过程中显示加载动画(比如CircularProgressIndicator),避免用户看到空白或异常UI。你可以添加一个isLoading状态变量,在_initializeApp()开始时设为true,完成后设为false,然后在build()方法中根据这个状态切换UI。
内容的提问来源于stack exchange,提问作者user3835604
相关产品推荐
相关产品推荐

