之前一起学习了 Cubit
,现在进一步学习 Bloc
首先应该了解一下 Cubit
与 Bloc
各自的优势,以便按需使用
从上面两图可以看出,在使用cubit
时,UI通过function
通知cubit
进行数据处理和state
更新,而使用bloc
时,则是通过event
来通知bloc
进行数据处理和state
更新。
Cubit
的优势:简单
创建一个 Cubit
时,只需要定义状态以及我们想要公开的改变状态的函数
创建一个 Bloc
时,必须定义状态、事件和 EventHandler
Bloc
的优势可溯源
可以查看什么事件引发了状态改变。
能够控制和转换事件的传入流
像下面的样子,就很轻松实现防抖的效果:
EventTransformer<T> debounce<T>(Duration duration) {
return (events, mapper) => events.debounceTime(duration).flatMap(mapper);
}
CounterBloc() : super(0) {
on<Increment>(
(event, emit) => emit(state + 1),
transformer: debounce(const Duration(milliseconds: 300)),
);
}
Bloc
abstract class CounterEvent {}
// 定义事件
class CounterIncrementPressed extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0){// 可以指定初始状态,此处0
on<CounterIncrementPressed>((event, emit) { //EventHandler 事件处理函数
// 可以通过 state getter 方法访问 bloc 的当前状态和通过 emit(state + 1) 改变状态.
emit(state + 1);
});
// 可以重写onchange 来观察状态的改变
@override
void onChange(Change<int> change) {
super.onChange(change);
print(change);
//输出Change { currentState: 0, nextState: 1 }
}
//通过重写onTransition 我们还可以观察到时什么事件出发了本次状态改变
@override
void onTransition(Transition<CounterEvent, int> transition) {
super.onTransition(transition);
print(transition);
// 输出Transition { currentState: 0, event: Instance of 'CounterIncrementPressed', nextState: 1 }
}
@override // bloc独有的,可以观察事件
void onEvent(CounterEvent event) {
super.onEvent(event);
print(event);
}
}
}
这里有两点需要注意:
Bloc 不可以直接发出状态,所有状态都应该是通过EventHandler函数发出的。
Bloc 和 Cubits 都会忽略重复的状态,也就是说如果currentState与nextState一致,则本次状态变化会被忽略。
除了在Bloc
类里面重写方法来观察状态,也可以和之前一样也可以通过将观察部分单独写在BlocObserver
类中:
触发时,先触发Bloc
本地的方法,然后再触发BlocObserver
的全局方法。
class SimpleBlocObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print('${bloc.runtimeType} $transition');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
print('${bloc.runtimeType} $error $stackTrace');
super.onError(bloc, error, stackTrace);
}
@override
void onEvent(Bloc bloc, Object? event) {
super.onEvent(bloc, event);
print('${bloc.runtimeType} $event');
}
@override
void onError(Object error, StackTrace stackTrace) {
print('$error, $stackTrace');
super.onError(error, stackTrace);
}
}
Future<void> main() async {
BlocOverrides.runZoned(
() {
CounterBloc()
..add(CounterIncrementPressed())
..close();
},
blocObserver: SimpleBlocObserver(),
);
}