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

Flutter中点击IconButton如何持久化_isDone状态至SQFlite数据库?

解决Flutter中Todo状态无法持久化及返回页面重置的问题

我来帮你排查并解决这个问题,你的代码里有几个关键问题导致状态无法正确保存和恢复,咱们一步步来修复:

1. 数据库初始化后被错误关闭

你的_onCreate方法最后调用了db.close(),这会导致数据库刚创建完成就被关闭,后续所有的更新、查询操作都会因为连接断开而失败。必须删掉这行代码:

FutureOr<void> _onCreate(Database db, int version) async {
  await db.execute('''create table $tableName(
    $columnId integer primary key,
    $columnThing text not null,
    $columnIsDone integer)''');
  await db.execute('''create table $tableName2(
    $columnId2 integer primary key,
    $columnThing2 text not null,
    $columnDate text not null,
    $columnTitle text)''');
  print('right');
  // 移除 db.close()!数据库连接会由SQFlite自动管理
}

2. 更新数据库时未指定条件,导致批量修改所有记录

你的updateTodo方法没有添加where条件,这会把表中所有Todo的isDone都改成同一个值,完全不符合预期。必须指定根据id更新单条记录:

Future<int> updateTodo(Todonote todonote) async {
  var d = await db;
  var res = await d.update(
    tableName,
    todonote.toMap(),
    where: '$columnId = ?', // 只更新匹配当前id的记录
    whereArgs: [todonote.id], // 传入当前Todo的id作为条件参数
  );
  print('成功更新 $res 条记录');
  return res;
}

3. 页面返回后未重新加载最新数据

当你跳转到其他页面再返回时,当前页面的_list还是内存中的旧数据,并没有从数据库读取最新状态。需要在页面初始化或返回时重新加载数据:

方法一:在initState中初始化加载

@override
void initState() {
  super.initState();
  _loadTodosFromDb(); // 页面启动时从数据库加载数据
}

Future<void> _loadTodosFromDb() async {
  var dbInstance = await widget.db.initDb();
  List<Map<String, dynamic>> todoMaps = await dbInstance.query(widget.db.tableName);
  setState(() {
    _list = todoMaps.map((map) => Todonote.fromMap(map)).toList();
  });
}

方法二:跳转返回后触发重新加载

如果是通过Navigator.push跳转页面,返回时可以用then方法触发数据刷新:

// 跳转页面的代码修改为:
Navigator.push(context, MaterialPageRoute(builder: (context) => OtherPage()))
  .then((_) {
    // 从其他页面返回后,重新拉取最新数据
    _loadTodosFromDb();
  });

4. 异步保存操作需等待同步

你的_saveTodo1是异步方法,但点击事件中没有用await,可能导致状态更新与数据库保存不同步,建议加上await保证顺序:

onPressed: () async { // 添加async关键字
  setState(() {
    _list[i].isDone = !_list[i].isDone;
  });
  // 等待数据库保存完成
  await _saveTodo1(_list[i].thing, _list[i].isDone);
}

额外检查:Todonote的映射方法是否正确

确保Todonote类的fromMap和toMap方法正确处理isDone字段(SQFlite不支持bool类型,需转成1/0):

class Todonote {
  int id;
  String thing;
  bool isDone;

  Todonote({required this.id, required this.thing, required this.isDone});

  // 转成数据库可存储的Map
  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'thing': thing,
      'isDone': isDone ? 1 : 0, // bool转整数
    };
  }

  // 从数据库Map转成Todonote对象
  static Todonote fromMap(Map<String, dynamic> map) {
    return Todonote(
      id: map['id'],
      thing: map['thing'],
      isDone: map['isDone'] == 1, // 整数转bool
    );
  }
}

按照以上步骤修改后,Todo的状态就能正确持久化到SQFlite数据库,跳转页面返回后也会加载最新的状态,不会再出现重置问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:37:36