小菜剛學習了 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 的一種封裝;
現在針對狀態管理的方式還有很多其他方式,小菜認為無需強制使用某一種,選擇適合自己對就好;
小菜對 Bloc 的嘗試暫時告一個段落,對於更高階的用法在實際應用中再進行嘗試和學習;如有錯誤,請多多指導!
來源: 阿策小和尚