Flutter Bloc 状态管理示例

一个 Dart 包,用于帮助实现 BLoC 模式。

概述

此包的目的是简化 BLoC(Business Logic Component)设计模式的实现。

此设计模式有助于分离表示层与业务逻辑。遵循 BLoC 模式可以促进可测试性和可重用性。该包抽象了模式的反应性方面,使开发人员能够专注于编写业务逻辑。

Cubit

Cubit 是一个扩展了 BlocBase 的类,可以扩展以管理任何类型的状态。Cubit 需要一个初始状态,该状态将在调用 emit 之前存在。Cubit 的当前状态可以通过 state getter 访问,并且可以通过调用 emit 并传入新状态来更新 cubit 的状态。Cubit 中的状态更改始于预定义的函数调用,这些调用可以使用 emit 方法输出新状态。onChange 在状态更改发生之前被调用,并包含当前状态和下一个状态。

创建 Cubit

/// 一个管理 int 作为状态的 CounterCubit。 class CounterCubit extends Cubit<int> { /// CounterCubit 的初始状态为 0。 CounterCubit() : super(0); /// 当调用 increment 时, /// 通过 state 访问 cubit 的当前状态, /// 并通过 emit 发出新的 state。 void increment() => emit(state + 1); }

使用 Cubit

void main() { /// 创建一个 CounterCubit 实例。 final cubit = CounterCubit(); /// 通过 state 访问 cubit 的状态。 print(cubit.state); // 0 /// 与 cubit 交互以触发状态更改。 cubit.increment(); /// 访问新的 state。 print(cubit.state); // 1 /// 在不再需要 cubit 时关闭它。 cubit.close(); }

观察 Cubit

可以重写 onChange 来观察单个 cubit 的状态更改。

可以重写 onError 来观察单个 cubit 的错误。

class CounterCubit extends Cubit<int> { CounterCubit() : super(0); void increment() => emit(state + 1); @override void onChange(Change<int> change) { super.onChange(change); print(change); } @override void onError(Object error, StackTrace stackTrace) { print('$error, $stackTrace'); super.onError(error, stackTrace); } }

BlocObserver 可用于观察所有 cubit。

class MyBlocObserver extends BlocObserver { @override void onCreate(BlocBase bloc) { super.onCreate(bloc); print('onCreate -- ${bloc.runtimeType}'); } @override void onChange(BlocBase bloc, Change change) { super.onChange(bloc, change); print('onChange -- ${bloc.runtimeType}, $change'); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { print('onError -- ${bloc.runtimeType}, $error'); super.onError(bloc, error, stackTrace); } @override void onClose(BlocBase bloc) { super.onClose(bloc); print('onClose -- ${bloc.runtimeType}'); } }

void main() { Bloc.observer = MyBlocObserver(); // 使用 cubits... }

Bloc

Bloc 是一个更高级的类,它依赖于事件来触发状态更改,而不是函数。Bloc 也扩展了 BlocBase,这意味着它具有与 Cubit 相似的公共 API。但是,Bloc 不是通过调用 Bloc 上的函数并直接发出新状态,而是接收事件并将传入的事件转换为传出的状态。Bloc 中的状态更改始于添加事件,该事件会触发 onEvent。然后,事件通过 EventTransformer 进行处理。默认情况下,每个事件都会并发处理,但可以提供自定义 EventTransformer 来修改传入的事件流。然后,该事件类型的所有已注册 EventHandlers 都会被调用。每个 EventHandler 负责响应事件发出零个或多个状态。最后,在状态更新之前调用 onTransition,它包含当前状态、事件和下一个状态。

创建 Bloc

/// CounterBloc 将响应的事件。 abstract class CounterEvent {} /// 通知 bloc 增加状态。 class CounterIncrementPressed extends CounterEvent {} /// 一个 CounterBloc,用于将 CounterEvent 转换为 int。 class CounterBloc extends Bloc<CounterEvent, int> { /// CounterBloc 的初始状态为 0。 CounterBloc() : super(0) { /// 当添加 CounterIncrementPressed 事件时, /// 通过 state 属性访问 bloc 的当前状态 /// 并通过 emit 发出新状态。 on<CounterIncrementPressed>((event, emit) => emit(state + 1)); } }

使用 Bloc

Future<void> main() async { /// 创建一个 CounterBloc 实例。 final bloc = CounterBloc(); /// 通过 state 访问 bloc 的状态。 print(bloc.state); // 0 /// 与 bloc 交互以触发状态更改。 bloc.add(CounterIncrementPressed()); /// 等待事件循环的下一个迭代 /// 以确保事件已被处理。 await Future.delayed(Duration.zero); /// 访问新的 state。 print(bloc.state); // 1 /// 在不再需要 bloc 时关闭它。 await bloc.close(); }

观察 Bloc

由于所有 Bloc 都像 Cubit 一样扩展 BlocBase,因此也可以在 Bloc 中重写 onChange 和 onError。

此外,Bloc 还可以重写 onEvent 和 onTransition。

每当向 Bloc 添加新事件时,都会调用 onEvent。

onTransition 类似于 onChange,但它除了 currentState 和 nextState 外,还包含触发状态更改的事件。

abstract class CounterEvent {} class CounterIncrementPressed extends CounterEvent {} class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0) { on<CounterIncrementPressed>((event, emit) => emit(state + 1)); } @override void onEvent(CounterEvent event) { super.onEvent(event); print(event); } @override void onChange(Change<int> change) { super.onChange(change); print(change); } @override void onTransition(Transition<CounterEvent, int> transition) { super.onTransition(transition); print(transition); } @override void onError(Object error, StackTrace stackTrace) { print('$error, $stackTrace'); super.onError(error, stackTrace); } }

BlocObserver 也可用于观察所有 bloc。

class MyBlocObserver extends BlocObserver { @override void onCreate(BlocBase bloc) { super.onCreate(bloc); print('onCreate -- ${bloc.runtimeType}'); } @override void onEvent(Bloc bloc, Object? event) { super.onEvent(bloc, event); print('onEvent -- ${bloc.runtimeType}, $event'); } @override void onChange(BlocBase bloc, Change change) { super.onChange(bloc, change); print('onChange -- ${bloc.runtimeType}, $change'); } @override void onTransition(Bloc bloc, Transition transition) { super.onTransition(bloc, transition); print('onTransition -- ${bloc.runtimeType}, $transition'); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { print('onError -- ${bloc.runtimeType}, $error'); super.onError(bloc, error, stackTrace); } @override void onClose(BlocBase bloc) { super.onClose(bloc); print('onClose -- ${bloc.runtimeType}'); } }

void main() { Bloc.observer = MyBlocObserver(); // 使用 bloc... }

GitHub

查看 Github