开源鸿蒙 Flutter for OpenHarmonysqflite搜索自动保存欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netDay2 的重点放在一件事把 sqflite 用得更像“真实笔记应用”。笔记多了要能搜用sqflite做标题/正文关键字查询LIKE写笔记要安全输入过程中自动落盘返回前再兜底保存一次底层还是sqflite的 insert/update本篇不新增第三方库沿用 Day1 的三方库组合sqflite fluttertoast path。1. 今天用到的第三方库各自负责什么 sqflite负责SQLite 查询/插入/更新搜索、自动保存最终都是它在写库/查库 fluttertoast负责把“保存成功/保存失败”这种状态给用户一个轻提示不挡操作 path负责拼接数据库文件路径Day1 已完成本篇继续沿用2. 搜索怎么写sqflite 的 query LIKE whereArgs搜索的目标很简单只搜未删除数据is_deleted 0标题或正文命中即可title LIKE ? OR content LIKE ?最近更新的排前面orderBy: updated_at DESC 文件lib/features/note/data/note_dao.dartFutureListNotesearchNotes(Stringkeyword,{int limit100})async{finaldbawait_db.database;finalk%${keyword.trim()}%;finalrowsawaitdb.query(notes,where:is_deleted ? AND (title LIKE ? OR content LIKE ?),whereArgs:[0,k,k],orderBy:updated_at DESC,limit:limit,);returnrows.map(_fromRow).toList(growable:false);}这段代码专门讲清楚 4 个点学会就能举一反三✅ 1为什么用db.query(...)query是 sqflite 的高频接口表名、where、排序、limit 都是参数不需要自己拼 SQL 字符串✅ 2为什么whereArgs必须用不要把关键字直接拼到where里容易出错也不利于排查whereArgs就是参数绑定title LIKE ?的?对应k✅ 3为什么k要写成%关键字%LIKE的包含匹配写法%表示任意字符串如果只想前缀匹配可以用关键字%✅ 4为什么要orderBy updated_at DESC笔记类列表通常“最近编辑的在前面”搜索结果也一样 截图位建议准备 3 张3. 搜索框怎么写避免每个字都触发一次 sqflite 查询如果输入一个字就查一次库sqflite的查询会变得很频繁体验会抖。处理方式很朴素防抖停 300ms 再查。 文件lib/features/note/ui/notes_list_page.dartTimer?_searchDebounce;latefinalTextEditingController_searchController;FutureListNote_loadNotes(){finalkeyword_searchController.text.trim();if(keyword.isEmpty){return_repo.listNotes();}return_repo.searchNotes(keyword);}void_onSearchChanged(String_){_searchDebounce?.cancel();_searchDebounceTimer(constDuration(milliseconds:300),(){if(!mounted)return;_reload();});}这里和sqflite的关系是_repo.searchNotes(keyword)最终会走到NoteDao.searchNotes(...)防抖的意义就是“减少 sqflite 的 query 调用次数”4. 自动保存怎么写核心是把 sqflite 的 insert/update 调用节奏做对自动保存不是“疯狂写库”目标是两条输入停下来一小段时间落盘一次防抖返回页面前再兜底落盘一次这背后对应的就是 sqflite 的两类写操作第一次insert新建一条 note后续update持续更新同一条 note4.1 防抖保存800ms 不输入就写一次库 文件lib/features/note/ui/note_editor_page.dartTimer?_autoSaveDebounce;bool _dirtyfalse;void_scheduleAutoSave(){_dirtytrue;_autoSaveDebounce?.cancel();_autoSaveDebounceTimer(constDuration(milliseconds:800),()async{if(!mounted)return;await_persist(showToastOnEmpty:false,showToastOnSuccess:false);});}这段写法的好处不是每次输入都写库而是“停下来再写”sqflite写库次数减少体验更稳4.2 持久化函数把 create/update 封装成一个入口 文件lib/features/note/ui/note_editor_page.dartbool _savingfalse;bool _queuedSavefalse;Note?_note;Futurevoid_persist({required bool showToastOnEmpty,required bool showToastOnSuccess,})async{if(!_dirty_note!null)return;if(_saving){_queuedSavetrue;return;}finaltitle_titleController.text;finalcontent_contentController.text;if(title.trim().isEmptycontent.trim().isEmpty){if(showToastOnEmpty)awaitshowToast(内容为空未保存);return;}setState(()_savingtrue);try{finalexisting_note;if(existingnull){finalcreatedawaitwidget.repo.create(title:title,content:content);_notecreated;}else{awaitwidget.repo.update(id:existing.id!,title:title,content:content,createdAt:existing.createdAt,);}_dirtyfalse;if(showToastOnSuccess)awaitshowToast(已保存);}catch(e){awaitshowToast(保存失败$e);}finally{if(mounted)setState(()_savingfalse);if(mounted_queuedSave){_queuedSavefalse;await_persist(showToastOnEmpty:false,showToastOnSuccess:false);}else{_queuedSavefalse;}}}这里最关键的是它把 sqflite 的写库“节奏”控制住了。✅ 1第一次自动保存为什么能成功existing null时走repo.create(...)create最终会走到 DAO 的insert(...)sqflite insert插入成功后把_note赋值后面就不会重复 insert✅ 2为什么不会并发写库_saving期间如果又来了保存请求就把_queuedSave标记为 true本轮保存结束后再跑下一轮 persist串行写库✅ 3fluttertoast 在这里怎么用自动保存默认不弹“已保存”避免打扰只有点击保存按钮时才showToast(已保存)失败一定 toast否则用户以为保存了其实没写进去5. 返回兜底保存确保最后一段输入不会丢 文件lib/features/note/ui/note_editor_page.dartreturnPopScope(canPop:false,onPopInvokedWithResult:(didPop,result){if(didPop)return;_onBackPressed();},child:Scaffold(appBar:AppBar(leading:IconButton(onPressed:_onBackPressed,icon:constIcon(Icons.arrow_back),),),),);_onBackPressed()做的事很直接取消防抖计时器 → 如果脏数据未落盘则 persist 一次 → 再退出页面。 截图位建议准备 2 张![Day2-编辑输入中](图_day2_editing.png) ![Day2-自动保存后列表更新时间变化](图_day2_autosave_list.png)6. 自测清单Day2 搜索输入关键字能命中标题/正文清空关键字后恢复完整列表连续输入时不卡顿防抖生效 自动保存新建页输入一段内容不点保存直接返回 → 再进列表仍能看到内容编辑已有笔记停 1 秒左右返回 → 列表更新时间变更快速连续输入时不会卡死/不会报错串行写库生效7. 下一步Day3 方向Day3 适合写一篇更“排错向”的内容sqflite 锁库、并发写入、迁移失败如何复现与定位。