Claude-skill-registry event-listener-container
为Flutter插件视图添加事件监听容器,自动管理事件订阅/取消订阅生命周期,避免内存泄漏并减少约84%的模板代码。适用场景:(1) 插件视图需要响应全局事件更新UI,(2) 需要避免手动管理订阅导致的内存泄漏,(3) 简化事件监听实现
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/event-listener-container" ~/.claude/skills/majiayu000-claude-skill-registry-event-listener-container && rm -rf "$T"
manifest:
skills/data/event-listener-container/SKILL.mdsource content
EventListenerContainer
为Flutter插件视图添加事件监听容器,自动管理事件订阅生命周期。
Workflow
1. Analyze Target File
识别以下内容:
- State class 或 StatelessWidget
- 需要监听的事件名称列表(如
,task_added
)task_updated - UI 更新逻辑(
或控制器方法调用)setState()
2. Add Import
import 'package:Memento/widgets/event_listener_container.dart';
3. Wrap UI with EventListenerContainer
在需要响应事件的 UI 外层包裹组件:
EventListenerContainer( events: ['task_added', 'task_updated', 'task_deleted'], onEvent: () => setState(() {}), child: MyContentWidget(), )
4. Combine with AnimatedBuilder (Optional)
当同时依赖控制器状态和事件时:
EventListenerContainer( events: ['task_added', 'task_updated', 'task_deleted'], onEvent: () {}, // 事件触发但不直接更新 child: AnimatedBuilder( animation: myController, builder: (context, _) { return MyContentWidget(data: myController.data); }, ), )
5. Multiple Independent Listeners
同一页面可以有多个独立的监听器:
Column( children: [ // 监听数据变更事件 EventListenerContainer( events: ['data_changed'], onEvent: () => setState(() => _dataVersion++), child: DataDisplayWidget(), ), // 监听UI相关事件 EventListenerContainer( events: ['theme_changed', 'locale_changed'], onEvent: () => _refreshTheme(), child: ThemedWidget(), ), ], )
6. Conditional Update (Optional)
在
onEvent 中添加条件判断:
EventListenerContainer( events: ['item_added', 'item_updated', 'item_deleted'], onEvent: () { final eventName = EventManager.instance.getLatestEventName() ?? ''; if (eventName == 'item_deleted' && shouldSkipDeleteUpdate) { return; } setState(() {}); }, child: MyContentWidget(), )
Detection Patterns
Event Names
查找以下模式的事件名称:
| 事件类型 | 命名示例 | 说明 |
|---|---|---|
| 添加 | , | 使用过去式 |
| 更新 | , | 使用过去式 |
| 删除 | , | 使用过去式 |
| 完成 | , | 使用过去式 |
| 状态变更 | , | 使用过去式 |
Controller Integration
查找以下模式:
- 控制器继承自
ChangeNotifier - 使用
响应控制器变化AnimatedBuilder - 控制器有
或类似方法refreshFromRemote()
Comparison: Manual vs EventListenerContainer
Manual Approach (Before)
class MyView extends StatefulWidget { const MyView({super.key}); @override State<MyView> createState() => _MyViewState(); } class _MyViewState extends State<MyView> { final List<(String, void Function(EventArgs))> _subscriptions = []; @override void initState() { super.initState(); _registerListeners(); } void _registerListeners() { void handler1(EventArgs args) { if (mounted) setState(() {}); } EventManager.instance.subscribe('task_added', handler1); _subscriptions.add(('task_added', handler1)); // ... 更多事件 } @override void dispose() { for (final (eventName, handler) in _subscriptions) { EventManager.instance.unsubscribe(eventName, handler); } super.dispose(); } @override Widget build(BuildContext context) { return Column(children: [...]); } }
EventListenerContainer (After)
class MyView extends StatelessWidget { const MyView({super.key}); @override Widget build(BuildContext context) { return EventListenerContainer( events: ['task_added', 'task_updated', 'task_deleted'], onEvent: () => setState(() {}), child: Column(children: [...]), ); } }
代码量对比:
- 手动方式:约 50 行
- EventListenerContainer:约 8 行
- 减少约 84% 的模板代码
Best Practices
1. Minimize Scope
只在需要响应事件的最小 UI 区域使用,避免不必要的重建。
2. Group Related Events
将相关事件分组,不要一次性监听所有事件。
3. Combine with Controller
对于复杂逻辑,将更新逻辑封装在控制器中,
onEvent 只调用控制器方法:
EventListenerContainer( events: ['external_sync_event'], onEvent: () => myController.refreshFromRemote(), child: AnimatedBuilder( animation: myController, builder: (context, _) => ListView(...), ), )
4. Debounce Updates (Optional)
如果多个事件可能连续触发,考虑使用防抖:
bool _isUpdating = false; EventListenerContainer( events: ['batch_update'], onEvent: () { if (_isUpdating) return; _isUpdating = true; WidgetsBinding.instance.addPostFrameCallback((_) { _isUpdating = false; setState(() {}); }); }, child: MyContentWidget(), )
Troubleshooting
事件触发了但 UI 没有更新?
检查:
是否正确包裹了目标 UIEventListenerContainer
回调中是否调用了onEvent
或触发更新的方法setState()
如何获取事件参数?
通过
EventManager.instance.getLatestEvent() 获取:
EventListenerContainer( events: ['item_added'], onEvent: () { final latestEvent = EventManager.instance.getLatestEvent('item_added'); if (latestEvent != null && latestEvent is ItemEventArgs) { print('添加的项目ID: ${latestEvent.itemId}'); } setState(() {}); }, child: MyContentWidget(), )
多个监听器会重复触发吗?
不会。每个
EventListenerContainer 都是独立的订阅者,只会更新各自的子树。
Notes
- 在
自动订阅,initState
自动取消订阅dispose - Debug 模式下自动打印事件收发日志
- 多个
独立工作,不会相互干扰EventListenerContainer - 使用中文注释与现有代码库保持一致
- 使用
验证代码flutter analyze