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