Flutter 状态管理之Bloc上
Posted 小猪快跑22
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 状态管理之Bloc上相关的知识,希望对你有一定的参考价值。
前言:Flutter 的状态管理插件有很多,比如 Provider,GetX 还有本篇要讲述的 Bloc 。Bloc 目前最新的版本是 flutter_bloc: ^8.0.1
。
BLoC 依赖 Stream和 StreamController实现,组件通过Sinks发送更新状态的事件,然后再通过 Streams通知其他组件更新。事件处理和通知刷新的业务逻辑都是由 BLoC 完成,从而实现业务逻辑与 UI 层的分离,并且逻辑部分可以做到复用。
之前我们更新数据通常是通过 setState
的方式实现的,这种会刷新整个页面,而使用 Bloc 只会刷新想要更新的UI部分。下面会通过几个例子来说明下。
一、使用 Bloc 来实现计数器且把数据传递给跳转的页面
计算器要实现加减一的功能,所以先定义2个 Event,且都继承 CounterEvent ,如下:
// 定义 event 的基类
abstract class CounterEvent
// 加1的 event
class IncrementEvent extends CounterEvent
// 减1的event
class DecrementEvent extends CounterEvent
然后定义一个 CounterBloc 如下:
/// 表示通过 Bloc 发送的事件只能是 CounterEvent, 返回值是 int
class CounterBloc extends Bloc<CounterEvent, int>
CounterBloc(int initialState) : super(initialState)
/// 减1的事件就是把当前的 state - 1
on<DecrementEvent>((event, emit)
/// 把对应的状态发送出去,在页面中就可以通过 BlocBuilder 来观察数据的改变
emit(state - 1);
);
/// 加1的事件就是把当前的 state + 1
on<IncrementEvent>((event, emit)
emit(state + 1);
);
页面具体的代码如下:
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
/// 要使用 BlocProvider 来提供 Bloc
home: BlocProvider<CounterBloc>(
create: (BuildContext context)
return CounterBloc(0);
,
child: CounterPage(),
),
);
class CounterPage extends StatelessWidget
@override
Widget build(BuildContext context)
CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
print(
"---------------------- CounterPage build ----------------------- $counterBloc.hashCode");
return Scaffold(
appBar: AppBar(
title: Text('test bloc '),
),
body: Container(
width: double.infinity,
child: Column(
children: [
/// 当增加或者减少计数时,只会局部更新 BlocBuilder ,不会整个刷新 build
BlocBuilder<CounterBloc, int>(
builder: (BuildContext context, int count)
print(
"---------------------- BlocBuilder build -----------------------");
return Text(
'当前计数: $count',
style: TextStyle(fontSize: 24),
);
,
buildWhen: (previous, next)
/// 这样写只有 increment 才有用,用来控制触发刷新的逻辑
return previous < next;
,
),
SizedBox(
height: 12,
),
ElevatedButton(
onPressed: ()
counterBloc.add(IncrementEvent());
,
child: Text(
'increment',
),
),
ElevatedButton(
onPressed: ()
counterBloc.add(DecrementEvent());
,
child: Text(
'decrement',
),
),
ElevatedButton(
onPressed: ()
/// 需要 BlocProvider 的 context , 且 BlocProvider 的 create 中返回当前的 counterBloc
/// 如果你在 create 中 重新 new 一个 CounterBloc ,那么在 page2 中增加计数,不会刷新本页面的计数
Navigator.push(context, MaterialPageRoute(builder: (context)
return BlocProvider<CounterBloc>(
create: (BuildContext context)
return counterBloc;
,
child: BlocPage2(),
);
));
,
child: Text(
'jump page 2',
),
),
],
),
),
);
其中的 buildWhen 是过滤触发条件的,代码中有注释了。BlocPage2 的代码如下:
class BlocPage2 extends StatelessWidget
@override
Widget build(BuildContext context)
CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
print('xxxxxxxxxxxxxxx $counterBloc.hashCode ');
return Scaffold(
appBar: AppBar(
title: Text('BlocPage2'),
),
body: Container(
width: double.infinity,
child: Column(
children: [
BlocBuilder<CounterBloc, int>(
builder: (BuildContext context, int count)
return Text(
'page2 当前计数: $count',
style: TextStyle(fontSize: 24),
);
),
ElevatedButton(
onPressed: ()
counterBloc.add(IncrementEvent());
,
child: Text('add')),
],
),
),
);
BlocPage2 中改变了计数,返回到 CounterPage 页面时计数会同步更新。
结语:本篇这里就结束了,下篇会通过一个真正的例子来说明 Bloc 是怎么做到 UI 和业务逻辑分离的,会有真正的网络请求和页面的刷新。
以上是关于Flutter 状态管理之Bloc上的主要内容,如果未能解决你的问题,请参考以下文章