小菜剛學習了 FlutterBloc 的基本用法,使用的場景還很簡單,主要是單一 Bloc 的應用,今天小菜繼續嘗試多個 Bloc 共用的場景;
小菜繼續完善前兩節的 Demo,添加了随機變更背景色的功能(并沒有實際意義,僅為了學習新知識點而已);
FlutterBloc
MultiBlocProvider
對于多個 Bloc 的應用場景,小菜嘗試了如下三種方式:
方案一:
在 build() 外建立和初始化 Bloc;小菜認為這種方式一定程度上擴大了 Bloc 的作用域;
NumberBloc _numBloc = NumberBloc();
ColorBloc _colorBloc = ColorBloc();
@override
Widget build(BuildContext context) {
return BlocBuilder<NumberBloc, int>(
bloc: _numBloc,
condition: (previousState, state) {
print('BlocPage.condition->$previousState==$state');
return state <= 30 ? true : false;
},
builder: (context, count) {
return BlocBuilder<ColorBloc, Color>(
bloc: _colorBloc,
builder: (context, color) {
return Scaffold(
appBar: AppBar(title: Text('Bloc Page'), actions: <Widget>[_settingWid()]),
body: Container(color: _colorBloc.state, child: _numberWid()),
floatingActionButton: _floatingWid());
});
});
}
方案二:
通過多個 BlocProvider 嵌套方式對 Bloc 進行建立;小菜認為這種方式嵌套層級較多,略微有一些繁瑣;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => _numBloc = NumberBloc(),
child: BlocBuilder<NumberBloc, int>(
bloc: _numBloc,
condition: (previousState, state) {
print('BlocPage.condition->$previousState==$state');
return state <= 30 ? true : false;
},
builder: (context, count) {
return BlocProvider(
create: (BuildContext context) => _colorBloc = ColorBloc(),
child: BlocBuilder<ColorBloc, Color>(
bloc: _colorBloc,
builder: (context, color) {
return Scaffold(
appBar: AppBar(title: Text('Bloc Page'), actions: <Widget>[_settingWid()]),
body: Container(color: _colorBloc.state, child: _numberWid()),
floatingActionButton: _floatingWid());
}));
}));
}
方案三:
便是采用 MultiBlocProvider 聚合綁定方式,作為一個 Widget 将 BlocProvider 方式聚合建立和初始化,小菜更傾向于這種方式,層級更清晰簡潔;
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (BuildContext context) => _numBloc = NumberBloc()),
BlocProvider(create: (BuildContext context) => _colorBloc = ColorBloc())
],
child: BlocBuilder<NumberBloc, int>(
bloc: _numBloc,
condition: (previousState, state) {
print('BlocPage.condition->$previousState==$state');
return state <= 30 ? true : false;
},
builder: (context, count) {
return BlocBuilder<ColorBloc, Color>(
bloc: _colorBloc,
builder: (context, color) {
return Scaffold(
appBar: AppBar(title: Text('Bloc Page'), actions: <Widget>[_settingWid()]),
body: Container(color: _colorBloc.state, child: _numberWid()),
floatingActionButton: _floatingWid());
});
}));
}

MultiBlocListener
對于多個 Bloc 的場景,對于其 Bloc 的監聽也可以有多種方式;
對應于 BlocProvider 的方式,小菜合并前兩種,嘗試 listener 嵌套方式進行監聽;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => _numBloc = NumberBloc(),
child: BlocListener<NumberBloc, int>(
bloc: _numBloc,
listener: (context, state) => print('BlocListener--->NumberBloc--->$state'),
child: BlocBuilder<NumberBloc, int>(
bloc: _numBloc,
condition: (previousState, state) {
print('BlocPage.condition->$previousState==$state');
return state <= 30 ? true : false;
},
builder: (context, count) {
return BlocProvider(
create: (BuildContext context) => _colorBloc = ColorBloc(),
child: BlocListener<ColorBloc, Color>(
bloc: _colorBloc,
listener: (context, state) => print('BlocListener--->ColorBloc--->$state'),
child: BlocBuilder<ColorBloc, Color>(
bloc: _colorBloc,
builder: (context, color) {
return ScaffoldappBar: AppBar(title: Text('Bloc Page'), actions: <Widget>[_settingWid()]),
body: Container(color: _colorBloc.state, child: _numberWid()),
floatingActionButton: _floatingWid());
})));
})));
}
MultiBlocListener 作為一個 Widget,将 listener 聚合在一起;效果完全相同,但消除了嵌套提高了 Code 可讀性;
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvidercreate: (BuildContext context) => _numBloc = NumberBloc()),
BlocProvider(create: (BuildContext context) => _colorBloc = ColorBloc())
],
child: MultiBlocListener(
listeners: [
BlocListener<NumberBloc, int>(listener: (context, state) => print('BlocListener--->NumberBloc--->$state')),
BlocListener<ColorBloc, Color>(listener: (context, state) => print('BlocListener--->ColorBloc--->$state'))
],
child: BlocBuilder<NumberBloc, int>(
bloc: _numBloc,
condition: (previousState, state) {
print('BlocPage.condition->$previousState==$state');
return state <= 30 ? true : false;
},
builder: (context, count) {
return BlocBuilder<ColorBloc, Color>(
bloc: _colorBloc,
builder: (context, color) {
return Scaffold(
appBar: AppBar(title: Text('Bloc Page'), actions: <Widget>[_settingWid()]),
body: Container(color: _colorBloc.state, child: _numberWid()),
floatingActionButton: _floatingWid());
});
})));
}
小感想
小菜嘗試了 Provider 和 Bloc 兩種狀态管理工具,均是對 Stream 的操作,小菜認為各有各的優勢,不能互相替代;
Bloc 方式最大的優勢是把頁面 UI 與業務邏輯拆分的更清晰,不管是 MVC 或 MVP 方式都更友善的融入應用;Provider 的應用更加簡單,無需考慮拆分的情況;
小菜在了解源碼的時候發現一個有趣的現象,FlutterBloc 也是對 Provider 的一種封裝;
現在針對狀态管理的方式還有很多其他方式,小菜認為無需強制使用某一種,選擇适合自己對就好;
FlutterBloc 案例源碼小菜對 Bloc 的嘗試暫時告一個段落,對于更進階的用法在實際應用中再進行嘗試和學習;如有錯誤,請多多指導!
來源: 阿策小和尚