Flutter学习 - Bloc - 04 Bloc的使用
本文主要介绍下Bloc的使用和介绍以及和Cubit的区别
之前我们介绍了使用Cubit来处理数据,那么Bloc呢?
1. Bloc
Bloc相比Cubit是一个更高的类,Cubit
我们知道通过公开
触发状变化的函数
。而Bloc依赖事件来床触发状态的改变,Bloc页拓展了BlocBase
,所有和Cubit的API也是类似。Blocs不是在Bloc上调用函数然后直接发出一个新的状态,而是通过接收事件并且将传入的事件转化为状态输出
。
abstract class CounterExampleEvent{}
class AddEvent extends CounterExampleEvent {
}
class ReduceEvent extends CounterExampleEvent {
}
class CounterExampleBloc extends Bloc<CounterExampleEvent, int> {
CounterExampleBloc() : super(0)
}
2. 状态改变
我们实现逻辑,通过我们的Event
驱动
class CounterExampleBloc extends Bloc<CounterExampleEvent, int> {
CounterExampleBloc() : super(0) {
on<AddEvent>((event, emit) {
emit(state+1);
});
on<ReduceEvent>((event, emit) {
// TODO: implement event handler
state-1;
emit(state-1);
});
}
}
Bloc
要求我们通过 on<Event>
上注册事件处理程序 API, 而不是在 Cubit
中的功能. 事件处理程序负责将任何传入事件转换为零或多个传出状态.更新 EventHandler
来处理 AddEvent
事件.
事件我们可以通过 state
getter 方法访问 bloc 的当前状态和通过 emit(state + 1)
改变状态.
3. 使用
我们使用BlocProvider
进行初始化
class CounterExamplePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => CounterExampleBloc(),
child: Builder(builder: (context) => _buildPage(context)),
);
}
}
通过获取bloc 后对事件行为进行传入事件, bloc.add(AddEvent())
,由于 Bloc
类继承了 BlocBase
,因此我们可以随时通过 state
getter 来访问 bloc
的当前状态,就像使用 Cubit 一样。
Widget _buildPage(BuildContext context) {
final bloc = BlocProvider.of<CounterExampleBloc>(context);
return Scaffold(
appBar: AppBar(title: const Text('Bloc-Blocw范例')),
body: Center(
child: BlocBuilder<CounterExampleBloc, int>(
builder: (context, state) {
return Text(
'点击了 ${bloc.state} 次',
style: const TextStyle(fontSize: 30.0),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => bloc.add(AddEvent()),
child: const Icon(Icons.add),
),
);
}
4. Stream使用
就像 Cubit
一样,Bloc
是 Stream
的一种特殊类型,这意味着我们还可以订阅 Bloc
来实时更新其状态:
Widget _buildPage(BuildContext context) {
final bloc = BlocProvider.of<CounterExampleBloc>(context);
int count = 0;
bloc.stream.listen((event) { count = event*2;});
return Scaffold(
appBar: AppBar(title: const Text('Bloc-Counter范例')),
body: Center(
child: BlocBuilder<CounterExampleBloc, int>(
builder: (context, state) {
return Text(
'点击了 $count 次',
style: const TextStyle(fontSize: 30.0),
);
},
),
),
}
我们通过监听可以处理我们 自定义数据,当我们不想再接收更新时,在订阅上调用 cancel
,并关闭 Bloc
。
5. 观察
由于所有 Bloc
都扩展了 BlocBase
,因此我们可以使用 onChange
观察 Bloc
的所有状态变化。
@override
void onChange(Change<int> change) {
super.onChange(change);
print(change);
}
- onTransition
Bloc
和 Cubit
之间的主要区别因素是,由于 Bloc
是事件驱动的,因此我们也能够捕获有关触发状态更改的信息。
我们可以通过重写 onTransition
来做到这一点。
@override
void onTransition(Transition<CounterExampleEvent, int> transition) {
super.onTransition(transition);
print(transition);
}
onTransition
在 onChange
之前被调用,并且包含触发从 currentState
到 nextState
改变的事件。
6. 观察者
我们可以在自定义 BlocObserver
中重写 onTransition
,以观察从一个位置发生的所有过渡。
class TestBlocObserver 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);
}
}
使用的时候和Cubit类似,CounterExampleBloc初始化之前添加观察者
Bloc.observer = TestBlocObserver();
打印结果
首先调用 onTransition
(在全局之前先于本地),然后调用 onChange
Bloc
实例的另一个独特功能是,它们使我们能够重写 onEvent
,无论何时将新事件添加到 Bloc
都会调用 onEvent
。就像 onChange
和 onTransition
一样,onEvent
可以在本地或全局重写。
@override
void onEvent(CounterExampleEvent event) {
super.onEvent(event);
print(event);
}
在BlocObserver类中
@override
void onEvent(Bloc bloc, Object? event) {
super.onEvent(bloc, event);
print('${bloc.runtimeType} $event');
}
打印结果:
就会调用 onEvent
。本地 onEvent
在 BlocObserver
中的全局 onEvent
之后被调用。
7. Cubit和Bloc
简单逻辑使用Cubit。
使用 Cubit
的最大优点之一就是简单。当创建一个 Cubit
时,我们只需要定义状态以及我们想要公开的改变状态的函数即可。相比之下,创建 Bloc
时,我们必须定义状态、事件和 EventHandler
实现。这使得 Cubit
更容易理解,并且涉及的代码更少。
对于一些复杂情况使用Bloc。
使用 Bloc
的最大优势之一就是知道状态变化的顺序
以及触发这些变化的确切原因。对于对于应用程序功能至关重要的状态
,使用更多事件驱动的方法来捕获状态变化之外的所有事件可能会非常有益。
转载自:https://juejin.cn/post/7132466108879077413