You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何让ChangeNotifier触发不同的监听回调?

解决方法

你现在的核心问题是ChangeNotifier的notifyListeners()会触发所有注册的监听,但你需要区分是launchHand()还是changeTurn()触发的通知,分别调用不同方法。这里有两种实用方案:

方案一:通过事件类型标识区分触发源

  1. 先定义枚举标记不同的操作类型:
enum RoundAction { launchHand, changeTurn }
  1. 修改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();
  }
}
  1. 在_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类的每个操作单独设置监听回调,逻辑更直观:

  1. 修改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();
  }
}
  1. 在_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,提问作者نظامی گنجوی

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:10:54