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

Flutter sqflite存储数据重启后丢失问题求助

用药提醒App重启后数据丢失问题排查与修复

核心问题梳理

开发用药提醒App时使用sqflite存储数据,但每次重启App后数据丢失,手动判断数据库存在性的逻辑未生效,导致每次重启都重新创建数据库。以下是具体错误点及修复方案:


1. 未触发本地数据加载流程

MedicationProvider中定义了init()方法用于从数据库加载已有数据,但在App启动时从未调用该方法,导致每次重启后Provider的本地列表始终为空,无法展示已存储的数据。

修复方案:

在首页MedicationScreen的initState中调用Provider的初始化方法:

class MedicationScreenState extends State<MedicationScreen> {
  @override
  void initState() {
    super.initState();
    // 加载本地数据库数据
    Provider.of<MedicationProvider>(context, listen: false).init();
  }

  // 其他代码...
}

2. 数据库初始化逻辑冗余且错误

sqflite的openDatabase方法本身会自动处理数据库的创建与打开:若数据库不存在则执行onCreate创建,若已存在则直接打开。手动添加databaseExists判断完全多余,甚至可能因路径判断误差导致误判,触发重复创建逻辑。

修复方案:

简化DatabaseHelper的_initDatabase方法:

Future<Database> _initDatabase() async {
  final String path = await getDatabasesPath();
  final String dbPath = join(path, 'medications.db');
  // 移除多余的存在性判断,交由openDatabase自动处理
  return openDatabase(
    dbPath,
    version: 1,
    onCreate: _createDatabase,
  );
}

3. 数据操作顺序与参数不匹配

(1)新增数据逻辑顺序错误

当前addMedication先更新本地列表再插入数据库,若数据库插入失败,会导致本地列表与数据库数据不一致。且方法返回void但内部使用await,易引发异步执行问题。

修复方案:

先完成数据库插入,再更新本地列表:

Future<void> addMedication(Medication medication) async {
  final db = await database.database;
  // 获取插入后的自增ID
  final insertedId = await db.insert('medications', medication.toMap());
  // 更新Medication的ID(需确保模型有id字段及copyWith方法)
  final updatedMed = medication.copyWith(id: insertedId);
  _medications.add(updatedMed);
  notifyListeners();
}

(2)更新/删除数据的参数不匹配

  • updateMedication中,数据库where条件使用主键id,但whereArgs传入的是notificationIDs(非主键字段,类型可能不匹配),导致更新操作失效。
  • deleteMedication中,参数为String id,但数据库主键是integer类型,类型不匹配导致删除操作失效,且本地列表删除逻辑依赖notificationIDs而非数据库主键,导致数据不同步。

修复方案:

修改更新与删除逻辑,统一使用数据库主键id:

// 更新数据
Future<void> updateMedication(Medication medication) async {
  final db = await database.database;
  await db.update(
    'medications',
    medication.toMap(),
    where: 'id = ?',
    whereArgs: [medication.id], // 使用数据库主键
  );
  final index = _medications.indexWhere((e) => e.id == medication.id);
  if (index != -1) {
    _medications[index] = medication;
    notifyListeners();
  }
}

// 删除数据
Future<void> deleteMedication(int id) async { // 参数改为int类型
  final db = await database.database;
  await db.delete(
    'medications',
    where: 'id = ?',
    whereArgs: [id],
  );
  _medications.removeWhere((e) => e.id == id);
  notifyListeners();
}

4. 模型字段映射一致性检查

确保Medication的toMap()/fromMap()方法与数据库表字段完全匹配:

  • 数据库主键id为integer类型,模型中需对应int类型字段
  • 避免将非数据库字段(如notificationIDs)写入toMap(),防止插入/更新时出现无效字段报错

内容的提问来源于stack exchange,提问作者Muhammad AsfandYar Amjad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:40:38