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

Flutter/Dart:如何在同步函数中执行异步数据库操作?

问题分析

你的核心问题有两个:

  • addToLoadedMonths仅执行了数据库插入操作,但没有将当前月份添加到内存中的loadedMonths列表,导致每次切换月份时,isAlreadyLoaded都会判断为false,重复执行加载逻辑,引发懒加载异常。
  • _onMonthChanged是同步函数,调用异步的addToLoadedMonths时未使用await,导致setState可能在数据库操作完成前执行,时序混乱进一步加剧了懒加载失效的问题。
修复步骤

1. 修改addToLoadedMonths函数

让它同时更新内存列表和数据库,并且返回Future以便外部等待执行完成:

Future<void> addToLoadedMonths(DateTime value) async {
  debugPrint("addToLoadedMonths called with value of: $value");
  // 先更新内存列表,避免重复判断
  if (!loadedMonths.any((date) => date.year == value.year && date.month == value.month)) {
    loadedMonths.add(value);
  }
  // 再执行数据库插入
  await LoadedMonthsDatabase.instance.insertDateTime(value);
}

2. 将_onMonthChanged改为异步函数

给函数加上async关键字,确保等待数据库操作完成后再更新UI:

Future<void> _onMonthChanged(DateTime? notRequired) async {
  DateTime value = DateTime(currentChosenDate.year, currentChosenDate.month);
  bool isAlreadyLoaded = loadedMonths.any((dateTime) =>
      dateTime.year == value.year && dateTime.month == value.month);

  if (!isAlreadyLoaded) {
    for (int i = 0; i < recurringEvents.length; i++) {
      DateTime dateCounter = value;
      while (dateCounter.month == value.month) {
        int weekday = dateCounter.weekday;
        bool isRecurringDay = false;

        // 用Map简化星期判断逻辑,替代大量if-else
        final weekdayMap = {
          DateTime.sunday: everySunday!,
          DateTime.monday: everyMonday!,
          DateTime.tuesday: everyTuesday!,
          DateTime.wednesday: everyWednesday!,
          DateTime.thursday: everyThursday!,
          DateTime.friday: everyFriday!,
          DateTime.saturday: everySaturday!,
        };
        isRecurringDay = weekdayMap[weekday] ?? false;

        if (isRecurringDay) {
          eventsList.add(
            NeatCleanCalendarEvent(
              recurringEvents[i].summary!,
              startTime: DateTime(
                dateCounter.year,
                dateCounter.month,
                dateCounter.day,
                chosenStartTime!.hour,
                chosenStartTime!.minute,
              ),
              endTime: DateTime(
                dateCounter.year,
                dateCounter.month,
                dateCounter.day,
                chosenEndTime!.hour,
                chosenEndTime!.minute,
              ),
            ),
          );
        }

        dateCounter = dateCounter.add(const Duration(days: 1));
      }
    }
    // 等待数据库操作完成后再更新UI
    await addToLoadedMonths(value);
    setState(() {});
  }
}

3. 补充初始化逻辑(必加)

应用启动时,需要从数据库读取已保存的月份到loadedMonths列表,避免重启后重复加载:

@override
void initState() {
  super.initState();
  _loadSavedLoadedMonths();
}

Future<void> _loadSavedLoadedMonths() async {
  // 假设你的数据库有获取所有已保存DateTime的方法,比如getAllDateTime
  List<DateTime> savedMonths = await LoadedMonthsDatabase.instance.getAllDateTime();
  setState(() {
    loadedMonths.addAll(savedMonths);
  });
}
关键提醒
  • 异步函数必须通过await等待执行完成,否则会导致代码时序混乱,UI更新不及时或逻辑错误。
  • 内存列表loadedMonths和数据库数据必须保持同步,否则会出现判断逻辑失效的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:16:13