Flutter:如何让ChangeNotifier触发不同的监听回调?
解决方法
你现在的核心问题是ChangeNotifier的notifyListeners()会触发所有注册的监听,但你需要区分是launchHand()还是changeTurn()触发的通知,分别调用不同方法。这里有两种实用方案:
方案一:通过事件类型标识区分触发源
- 先定义枚举标记不同的操作类型:
enum RoundAction { launchHand, changeTurn }
- 修改
Round类,添加存储最后触发操作的变量:
class Round extends ChangeNotifier { RoundAction? _lastAction; // 对外暴露最后触发的操作类型 RoundAction? get lastAction => _lastAction; void launchHand() { _currentIndex = 0; incrementHandNo(); _lastAction = RoundAction.launchHand; notifyListeners(); } void changeTurn() { _currentIndex = _currentIndex == 0 ? 1 : 0; _lastAction = RoundAction.changeTurn; notifyListeners(); } }
- 在
_BoardViewState里替换原监听器,统一根据操作类型调用对应方法:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _playerTakesTurn()); widget.roundController.launchHand(); if (players[widget.roundController.currentIndex].getPlayerName() == "Human") { widget.humanPlayer.enableTileTapsInHumansHand(); } // 替换原监听器为统一处理方法 widget.roundController.addListener(_handleRoundUpdate); } void _handleRoundUpdate() { switch(widget.roundController.lastAction) { case RoundAction.launchHand: newHandHasBegun(); break; case RoundAction.changeTurn: _playerTakesTurn(); break; default: // 无匹配操作时可忽略或做兜底处理 break; } }
方案二:给每个操作添加独立的回调监听
如果不想用枚举区分,也可以给Round类的每个操作单独设置监听回调,逻辑更直观:
- 修改
Round类,添加独立的回调管理方法:
class Round extends ChangeNotifier { // 存储launchHand的监听列表 final List<VoidCallback> _launchHandCallbacks = []; // 存储changeTurn的监听列表 final List<VoidCallback> _changeTurnCallbacks = []; // 注册launchHand监听 void addLaunchHandListener(VoidCallback callback) { _launchHandCallbacks.add(callback); } // 移除launchHand监听 void removeLaunchHandListener(VoidCallback callback) { _launchHandCallbacks.remove(callback); } // 注册changeTurn监听 void addChangeTurnListener(VoidCallback callback) { _changeTurnCallbacks.add(callback); } // 移除changeTurn监听 void removeChangeTurnListener(VoidCallback callback) { _changeTurnCallbacks.remove(callback); } void launchHand() { _currentIndex = 0; incrementHandNo(); // 触发所有launchHand的回调 for (final callback in _launchHandCallbacks) { callback(); } // 若其他地方需要通用通知,可保留notifyListeners() notifyListeners(); } void changeTurn() { _currentIndex = _currentIndex == 0 ? 1 : 0; // 触发所有changeTurn的回调 for (final callback in _changeTurnCallbacks) { callback(); } notifyListeners(); } }
- 在
_BoardViewState里注册对应监听,并在销毁时移除:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _playerTakesTurn()); widget.roundController.launchHand(); if (players[widget.roundController.currentIndex].getPlayerName() == "Human") { widget.humanPlayer.enableTileTapsInHumansHand(); } // 注册对应操作的监听 widget.roundController.addLaunchHandListener(newHandHasBegun); widget.roundController.addChangeTurnListener(_playerTakesTurn); } @override void dispose() { // 移除监听避免内存泄漏 widget.roundController.removeLaunchHandListener(newHandHasBegun); widget.roundController.removeChangeTurnListener(_playerTakesTurn); super.dispose(); }
两种方案都能实现你的需求:调用launchHand()时触发newHandHasBegun(),调用changeTurn()时触发_playerTakesTurn()。方案一更适合需要通用通知+操作区分的场景,方案二更适合每个操作对应独立回调的场景。
内容的提问来源于stack exchange,提问作者نظامی گنجوی
相关产品推荐
相关产品推荐

