AtomGit Flutter 鸿蒙客户端:dispose生命周期与资源释放
·
创建资源容易,忘记释放是常态。本文汇总 E-Brufen 中所有 dispose 场景,形成可复用的资源释放清单。
一、E-Brufen 中的五类资源
| 资源类型 | 示例 | 释放方法 |
|---|---|---|
| AnimationController | _pulse, _controller | .dispose() |
| Timer | _timer, _countdown | .cancel() |
| TextEditingController | _noteController | .dispose() |
| TabController | _tabController | .dispose() |
| ChangeNotifier listener | addListener 回调 | .removeListener() |
| Hive Box | _box | .close() |
二、DiaryPage:最复杂的 dispose

void dispose() {
widget.moodStorage.removeListener(_loadMoods); // 1. 解绑监听
_tabController.dispose(); // 2. 释放 Tab 控制器
_noteController.dispose(); // 3. 释放文本控制器
super.dispose(); // 4. 调用父类
}
释放顺序原则:先释放依赖方,再释放被依赖方。
removeListener 必须先执行——因为 _loadMoods 中使用了 setState,如果 State 已经被父类 dispose 了还触发 setState,就会崩溃。
三、BreathePage:Timer + AnimationController
// breathe_page.dart — 没有显式的 dispose(因为 BreathingCircle 是子 Widget)
// breathing_circle.dart
void dispose() {
_timer?.cancel(); // 1. 先取消 Timer(防止回调触发)
_controller.dispose(); // 2. 再释放 Controller
super.dispose();
}
★ Insight ─────────────────────────────────────_timer?.cancel()在_controller.dispose()之前执行是有意的顺序。如果先 dispose Controller,而 Timer 恰好在这之后触发(竞争条件),回调中会尝试操作已销毁的 Controller → 崩溃。先取消 Timer 消除了这个竞争窗口。─────────────────────────────────────────────────
四、SoundscapePage:双异步资源
void dispose() {
_pulse.dispose(); // AnimationController
_countdown?.cancel(); // Timer
super.dispose();
}
五、MoodStorage:数据层资源
// mood_storage.dart
void dispose() {
_box?.close(); // 关闭 Hive Box,释放文件句柄
super.dispose();
}
Hive Box 不关闭会导致文件句柄泄漏——虽然应用退出时 OS 会回收,但在长时间运行的应用中可能累积。
六、AppSettings:同样需要
// settings.dart
void dispose() {
_box?.close();
}
七、资源释放检查清单
在 code review 时,对每个 StatefulWidget 检查:
□ 有 AnimationController? → .dispose()
□ 有 Timer? → .cancel()
□ 有 TextEditingController? → .dispose()
□ 有 TabController? → .dispose()
□ 有 addListener? → .removeListener()
□ 有 FocusNode? → .dispose()
□ 有 ScrollController? → .dispose()
□ 有 StreamSubscription? → .cancel()
八、常见遗漏模式
遗漏 1:initState 中注册但忘记 dispose
// ❌ 常见错误
void initState() {
super.initState();
widget.model.addListener(_onChange);
// 忘记在 dispose 中 removeListener
}
遗漏 2:条件创建忘记条件释放
Timer? _timer;
void start() {
_timer = Timer.periodic(...);
}
void dispose() {
_timer?.cancel(); // ✅ 使用 ?. 安全操作符
super.dispose();
}
小结
资源释放是一个"对称性"问题——每一个 create/register/add/open 都需要对应的 dispose/cancel/remove/close。E-Brufen 的代码中,这个对称性保持得相当好。把它变成习惯,而不是事后补救。
作者简介:E-Brufen Dev,Flutter & 鸿蒙开发者,专注于跨平台移动应用开发与心理健康数字化,项目地址:AtomGit - E-Brufen。
更多推荐

所有评论(0)