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
相关产品推荐
相关产品推荐

