AsyncRedux观察器配置Skill asyncredux-observers

该技能涉及在AsyncRedux中设置观察器,用于调试和监控Flutter应用的状态管理。关键功能包括动作观察(ActionObserver)、状态变更跟踪(StateObserver)、错误处理(ErrorObserver)和模型重建监控(ModelObserver)。适用于移动开发中的状态管理优化、问题排查和数据分析,提升应用性能和可维护性。

移动开发 0 次安装 0 次浏览 更新于 3/19/2026

name: asyncredux-observers description: 设置观察器用于调试和监控。涵盖实现actionObservers用于分发日志记录、stateObserver用于状态变更跟踪、结合观察器与globalWrapError,以及使用观察器进行数据分析。

设置观察器用于调试和监控

AsyncRedux 提供了多种观察器类型,用于监控动作、状态变更、错误和部件重建。这些观察器在创建 Store 时配置。

观察器类型概述

观察器类型 用途
ActionObserver 监控动作分发(开始和结束)
StateObserver 监控动作后的状态变更
ErrorObserver 监控和处理动作错误
ModelObserver 监控部件重建(用于 StoreConnector)

使用观察器的 Store 配置

var store = Store<AppState>(
  initialState: AppState.initialState(),
  actionObservers: [ConsoleActionObserver()],
  stateObservers: [MyStateObserver()],
  errorObserver: MyErrorObserver(),
  modelObserver: DefaultModelObserver(),
);

ActionObserver

ActionObserver 监控动作何时分发以及何时完成。每个动作触发两次:开始(INI)和结束(END)。

ActionObserver 抽象类

abstract class ActionObserver<St> {
  void observe(
    ReduxAction<St> action,
    int dispatchCount, {
    required bool ini,
  });
}

参数

  • action:分发的动作实例
  • dispatchCount:此分发的顺序号
  • initrue 表示动作开始(INI 阶段),false 表示结束(END 阶段)

观察阶段

INI 阶段:动作分发开始。reducer 尚未修改状态。同步 reducer 可能在此阶段完成;异步 reducer 开始其异步过程。

END 阶段:reducer 已完成并返回新状态。状态修改现在可观察。

重要:接收 END 观察不保证所有 effects 已完成。未等待的异步操作可能继续运行并在之后分发额外动作。

内置 ConsoleActionObserver

AsyncRedux 提供 ConsoleActionObserver 用于开发调试:

var store = Store<AppState>(
  initialState: AppState.initialState(),
  actionObservers: kReleaseMode ? null : [ConsoleActionObserver()],
);

这会在控制台以黄色打印动作。在动作中覆盖 toString() 以显示额外信息:

class LoadUserAction extends AppAction {
  final String username;
  LoadUserAction(this.username);

  @override
  Future<AppState?> reduce() async {
    // ...
  }

  @override
  String toString() => 'LoadUserAction(username: $username)';
}

使用 Log.printer 进行格式化输出

var store = Store<AppState>(
  initialState: AppState.initialState(),
  actionObservers: [Log.printer(formatter: Log.verySimpleFormatter)],
);

自定义 ActionObserver 实现

class MyActionObserver implements ActionObserver<AppState> {
  @override
  void observe(
    ReduxAction<AppState> action,
    int dispatchCount, {
    required bool ini,
  }) {
    final phase = ini ? 'START' : 'END';
    print('[$phase] Action #$dispatchCount: ${action.runtimeType}');
  }
}

StateObserver

StateObserver 接收所有状态变更通知,允许您跟踪、记录或记录状态历史。

StateObserver 抽象类

abstract class StateObserver<St> {
  void observe(
    ReduxAction<St> action,
    St prevState,
    St newState,
    Object? error,
    int dispatchCount,
  );
}

参数

  • action:触发变更的动作
  • prevState:reducer 执行前的状态
  • newState:reducer 返回的状态
  • error:成功时为 null;否则包含抛出的错误
  • dispatchCount:顺序分发号

检测状态变更

使用 identical() 比较状态以检测实际变更:

bool stateChanged = !identical(prevState, newState);

用于日志记录的自定义 StateObserver

class StateLogger implements StateObserver<AppState> {
  @override
  void observe(
    ReduxAction<AppState> action,
    AppState prevState,
    AppState newState,
    Object? error,
    int dispatchCount,
  ) {
    final changed = !identical(prevState, newState);
    print('Action #$dispatchCount: ${action.runtimeType}');
    print('  状态变更: $changed');
    if (error != null) {
      print('  错误: $error');
    }
  }
}

用于撤销/重做的 StateObserver

一个常见用例是记录状态历史以支持撤销/重做功能:

class UndoRedoObserver implements StateObserver<AppState> {
  final List<AppState> _history = [];
  int _currentIndex = -1;
  final int maxHistorySize;

  UndoRedoObserver({this.maxHistorySize = 50});

  bool get canUndo => _currentIndex > 0;
  bool get canRedo => _currentIndex < _history.length - 1;

  @override
  void observe(
    ReduxAction<AppState> action,
    AppState prevState,
    AppState newState,
    Object? error,
    int dispatchCount,
  ) {
    // 跳过撤销/重做动作以避免记录导航
    if (action is UndoAction || action is RedoAction) return;

    // 跳过状态未变更的情况
    if (identical(prevState, newState)) return;

    // 如果正在导航,移除“未来”状态
    if (_currentIndex < _history.length - 1) {
      _history.removeRange(_currentIndex + 1, _history.length);
    }

    // 添加新状态
    _history.add(newState);
    _currentIndex = _history.length - 1;

    // 强制执行最大历史大小
    if (_history.length > maxHistorySize) {
      _history.removeAt(0);
      _currentIndex--;
    }
  }

  AppState? getPreviousState() {
    if (!canUndo) return null;
    _currentIndex--;
    return _history[_currentIndex];
  }

  AppState? getNextState() {
    if (!canRedo) return null;
    _currentIndex++;
    return _history[_currentIndex];
  }
}

ErrorObserver

ErrorObserver 监控所有动作抛出的错误,并可以抑制或允许它们传播。

错误处理流程

错误处理顺序为:

  1. wrapError()(动作级别)
  2. GlobalWrapError(应用级别)
  3. ErrorObserver(监控/日志记录)

ErrorObserver 实现

class MyErrorObserver<St> implements ErrorObserver<St> {
  @override
  bool observe(
    Object error,
    StackTrace stackTrace,
    ReduxAction<St> action,
    Store store,
  ) {
    // 记录错误
    print('错误在 ${action.runtimeType}: $error');
    print(stackTrace);

    // 发送到崩溃报告服务
    crashReporter.recordError(error, stackTrace, reason: action.runtimeType.toString());

    // 返回 true 以重新抛出错误,false 以抑制它
    return true;
  }
}

使用 ErrorObserver 的 Store 配置

var store = Store<AppState>(
  initialState: AppState.initialState(),
  errorObserver: MyErrorObserver<AppState>(),
);

结合 GlobalWrapError 使用

使用 GlobalWrapError 在错误到达 ErrorObserver 之前转换错误:

var store = Store<AppState>(
  initialState: AppState.initialState(),
  globalWrapError: MyGlobalWrapError(),
  errorObserver: MyErrorObserver<AppState>(),
);

class MyGlobalWrapError extends GlobalWrapError {
  @override
  Object? wrap(Object error, StackTrace stackTrace, ReduxAction<dynamic> action) {
    // 将平台错误转换为用户友好消息
    if (error is PlatformException) {
      return UserException('检查您的互联网连接').addCause(error);
    }
    return error;
  }
}

ModelObserver

ModelObserver 监控使用 StoreConnector 时的部件重建。这对于调试重建行为并确保高效状态更新很有用。

设置

var store = Store<AppState>(
  initialState: AppState.initialState(),
  modelObserver: DefaultModelObserver(),
);

控制台输出

DefaultModelObserver 打印重建信息:

Model D:1 R:1 = Rebuild:true, Connector:MyWidgetConnector, Model:MyViewModel{B}.
Model D:2 R:2 = Rebuild:false, Connector:MyWidgetConnector, Model:MyViewModel{B}.
Model D:3 R:3 = Rebuild:true, Connector:MyWidgetConnector, Model:MyViewModel{C}.
  • D:分发计数
  • R:重建计数
  • Rebuild:部件是否实际重建
  • Connector:StoreConnector 类型
  • Model:带有当前状态的 ViewModel

更好的输出配置

debug: this 传递给 StoreConnector 以启用连接器类型打印:

class MyWidgetConnector extends StatelessWidget with StoreConnector<AppState, MyViewModel> {
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, MyViewModel>(
      debug: this, // 启用 ModelObserver 输出
      converter: (store) => MyViewModel.fromStore(store),
      builder: (context, vm) => MyWidget(vm),
    );
  }
}

覆盖 ViewModel.toString() 以获取自定义诊断信息。

使用观察器进行数据分析

指标观察器模式

创建一个指标观察器,委托给特定动作的跟踪方法:

abstract class AppAction extends ReduxAction<AppState> {
  /// 在特定动作中覆盖以跟踪指标
  void trackEvent(MetricsService metrics) {}
}

class MetricsObserver implements StateObserver<AppState> {
  final MetricsService metrics;

  MetricsObserver(this.metrics);

  @override
  void observe(
    ReduxAction<AppState> action,
    AppState prevState,
    AppState newState,
    Object? error,
    int dispatchCount,
  ) {
    if (action is AppAction) {
      action.trackEvent(metrics);
    }
  }
}

然后在特定动作中覆盖 trackEvent

class PurchaseAction extends AppAction {
  final Product product;
  PurchaseAction(this.product);

  @override
  Future<AppState?> reduce() async {
    await purchaseService.buy(product);
    return state.copy(purchases: state.purchases.add(product));
  }

  @override
  void trackEvent(MetricsService metrics) {
    metrics.trackPurchase(productId: product.id, price: product.price);
  }
}

数据分析 ActionObserver

跟踪所有分发的动作以进行数据分析:

class AnalyticsObserver implements ActionObserver<AppState> {
  final AnalyticsService analytics;

  AnalyticsObserver(this.analytics);

  @override
  void observe(
    ReduxAction<AppState> action,
    int dispatchCount, {
    required bool ini,
  }) {
    // 仅开始时(ini)跟踪以避免重复计数
    if (ini) {
      analytics.trackEvent(
        'action_dispatched',
        parameters: {'action_type': action.runtimeType.toString()},
      );
    }
  }
}

完整示例:具有所有观察器的 Store

// observers.dart
class ConsoleStateObserver implements StateObserver<AppState> {
  @override
  void observe(
    ReduxAction<AppState> action,
    AppState prevState,
    AppState newState,
    Object? error,
    int dispatchCount,
  ) {
    final changed = !identical(prevState, newState);
    print('[$dispatchCount] ${action.runtimeType} - 变更: $changed');
    if (error != null) print('  错误: $error');
  }
}

class CrashReportingErrorObserver implements ErrorObserver<AppState> {
  @override
  bool observe(Object error, StackTrace stackTrace, ReduxAction<AppState> action, Store store) {
    // 不报告 UserExceptions(它们是预期的)
    if (error is! UserException) {
      FirebaseCrashlytics.instance.recordError(error, stackTrace);
    }
    return true; // 重新抛出错误
  }
}

// main.dart
void main() {
  final store = Store<AppState>(
    initialState: AppState.initialState(),
    // 仅在调试模式下启用控制台观察器
    actionObservers: kDebugMode ? [ConsoleActionObserver()] : null,
    stateObservers: kDebugMode ? [ConsoleStateObserver()] : null,
    // 始终启用错误观察器
    errorObserver: CrashReportingErrorObserver(),
    // 全局转换错误
    globalWrapError: MyGlobalWrapError(),
  );

  runApp(StoreProvider<AppState>(
    store: store,
    child: MyApp(),
  ));
}

多个观察器

您可以使用相同类型的多个观察器:

var store = Store<AppState>(
  initialState: AppState.initialState(),
  actionObservers: [
    ConsoleActionObserver(),
    AnalyticsObserver(analyticsService),
    PerformanceObserver(),
  ],
  stateObservers: [
    StateLogger(),
    UndoRedoObserver(),
    MetricsObserver(metricsService),
  ],
);

所有观察器将按列出的顺序被通知。

参考

文档中的 URL: