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:此分发的顺序号ini:true表示动作开始(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 监控所有动作抛出的错误,并可以抑制或允许它们传播。
错误处理流程
错误处理顺序为:
wrapError()(动作级别)GlobalWrapError(应用级别)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:
- https://asyncredux.com/flutter/miscellaneous/logging
- https://asyncredux.com/flutter/miscellaneous/metrics
- https://asyncredux.com/flutter/miscellaneous/observing-rebuilds
- https://asyncredux.com/flutter/miscellaneous/undo-and-redo
- https://asyncredux.com/flutter/advanced-actions/errors-thrown-by-actions
- https://asyncredux.com/flutter/advanced-actions/redux-action
- https://asyncredux.com/flutter/basics/store