Day8_开源鸿蒙_Flutter_for_OpenHarmony_get实战_笔记列表状态管理
本文介绍了如何利用GetX状态管理重构开源鸿蒙Flutter笔记应用的列表页逻辑。作者将原本分散在各处的刷新逻辑集中到NotesController中,通过Rx状态管理实现了搜索防抖、列表加载、删除置顶等核心功能。文章详细展示了控制器设计、状态字段定义、关键方法实现(如load()、onSearchChanged()等),以及如何将页面改造为使用Obx响应式组件。这种架构使UI层变得更简洁,业务逻
开源鸿蒙 Flutter for OpenHarmony:GetX 实战(笔记列表状态管理)
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
做到 Day7,离线笔记的功能已经不少了:搜索、自动保存、私密笔记、备份导入导出、置顶排序……
这时候很容易出现一个“代码层面”的问题:列表页的刷新逻辑越来越散。
- 搜索框变一下要刷新
- 导入成功要刷新
- 编辑页返回要刷新
- 左滑删除要刷新
- 置顶/取消置顶要刷新
如果每个地方都 setState(() { future = ... }),短期能跑,长期就会变难维护。
Day8 就把“列表页状态”收拢一下:用第三方库 get(GetX)做一个 NotesController,把加载/防抖/删除/置顶这些行为集中起来,让页面只负责 UI。
1. 今天用到的第三方库:get
GetX 在这篇只用它最常用的 3 个点:
Rx:可观察状态(loading / error / notes / keyword)Obx:状态变化自动刷新 UIGet.put / Get.delete:把控制器放到页面生命周期里
添加依赖:
flutter pub add get
2. 先把“状态字段”列清楚
列表页真实需要的状态其实就四个:
notes:当前要展示的笔记列表keyword:当前搜索关键字loading:是否正在加载(显示进度条)error:加载失败时的错误信息
把它们放进一个控制器里:
📌 文件:lib/features/note/ui/notes_controller.dart
class NotesController extends GetxController {
final NoteRepository _repo;
NotesController(this._repo);
final notes = <Note>[].obs;
final keyword = ''.obs;
final loading = false.obs;
final error = RxnString();
}
3. 核心:load()(决定到底查 list 还是 search)
列表的加载逻辑只有一条:
关键字为空 → listNotes();有关键字 → searchNotes(keyword)。
Future<void> load() async {
final k = keyword.value.trim();
loading.value = true;
error.value = null;
try {
final result = k.isEmpty ? await _repo.listNotes() : await _repo.searchNotes(k);
notes
..clear()
..addAll(result);
} catch (e) {
error.value = '$e';
} finally {
loading.value = false;
}
}
这样页面想刷新时,不需要关心“future 怎么重绑”,只要调用一次 controller.load()。
4. 搜索防抖也收拢:onSearchChanged()(停 300ms 再查库)
搜索输入每个字都查库,体验会抖。
做法还是 Day2 那套:防抖 300ms,只是这次把 Timer 放进 Controller,页面更干净。
void onSearchChanged(String text) {
keyword.value = text.trim();
_debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 300), () {
load();
});
}
清空搜索也收拢成一个方法:
Future<void> clearSearch() async {
keyword.value = '';
await load();
}
5. 删除 / 置顶:让页面只触发动作,不关心写库细节
页面里最烦的就是“点一下要写库,还要 toast,再刷新”。
这些非常适合收进 Controller。
5.1 删除
Future<void> delete(Note note) async {
final id = note.id;
if (id == null) return;
try {
await _repo.delete(id);
await showToast('已删除');
} catch (e) {
await showToast('删除失败:$e');
}
await load();
}
5.2 置顶/取消置顶
Future<void> togglePinned(Note note) async {
final id = note.id;
if (id == null) return;
final next = !note.pinned;
try {
await _repo.setPinned(id: id, pinned: next);
await showToast(next ? '已置顶' : '已取消置顶');
} catch (e) {
await showToast('操作失败:$e');
}
await load();
}
6. 页面改造:FutureBuilder → Obx
📌 文件:lib/features/note/ui/notes_list_page.dart
6.1 初始化 Controller(Get.put)
final db = AppDatabase.instance;
_repo = NoteRepository(NoteDao(db), NoteCrypto(db));
_controller = Get.put(NotesController(_repo));
页面销毁时删掉控制器(Get.delete):
void dispose() {
Get.delete<NotesController>();
_searchController.dispose();
super.dispose();
}
6.2 用 Obx 渲染三种状态:loading / error / list
Expanded(
child: Obx(() {
if (_controller.loading.value) {
return const Center(child: CircularProgressIndicator());
}
final err = _controller.error.value;
if (err != null) {
return Center(child: Text('加载失败:$err'));
}
final notes = _controller.notes;
if (notes.isEmpty) {
final keyword = _controller.keyword.value.trim();
if (keyword.isEmpty) return const Center(child: Text('暂无笔记,点右下角新增'));
return Center(child: Text('未找到与「$keyword」相关的笔记'));
}
return ListView.separated(
itemCount: notes.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (_, index) {
final note = notes[index];
...
},
);
}),
)
6.3 页面事件全部变成“调用控制器方法”
- 搜索框:
onChanged: _controller.onSearchChanged - 清空:
_controller.clearSearch() - 刷新:
onPressed: _controller.load - 删除:
onDismissed: (_) => _controller.delete(note) - 置顶:
onPressed: () => _controller.togglePinned(note)
到这里,页面就很像“纯 UI 组件”,业务动作集中在 Controller。
📷

7. 自测清单(Day8)
- 搜索输入:连续输入/删除字符,列表能跟着变化(防抖生效)
- 导入备份成功:返回列表自动刷新
- 编辑笔记返回:列表自动刷新
- 左滑删除:toast 正常 + 列表刷新
- 点星标:toast 正常 + 列表重新排序
更多推荐



所有评论(0)