Flutter學習筆記 狀態(tài)管理學習之bLoc
1.創(chuàng)建一個狀態(tài)管理
首先使用Stream來實現(xiàn)的bLoc狀態(tài)管理如果不手動回收就會一直占用資源,所以在設計之初就需要強調使用完成之后的回收;
abstract class BlocBase {
void dispose();
}
這里的Demo描述的是一個計數(shù)參數(shù)的管理:
class IncrementBloc implements BlocBase {
int _counter;
StreamController<int> _counterController = StreamController<int>.broadcast();
StreamSink<int> get _inAdd => _counterController.sink;
Stream<int> get outCounter => _counterController.stream;
StreamController _actionControll = StreamController.broadcast();
StreamSink get incrementCounter => _actionControll.sink;
IncrementBloc() {
_counter = 0;
_actionControll.stream.listen(_handleLogic);
}
void _handleLogic(data) {
_counter += 1;
_inAdd.add(_counter);
}
@override
void dispose() {
_actionControll.close();
_counterController.close();
}
}
解釋一下設計的屬性:
-
StreamController<int>:Stream管理類,這里主要控制的是計數(shù)參數(shù)的變化以及監(jiān)聽; -
_inAdd:計數(shù)寫入 -
outCounter:計數(shù)輸出 -
_actionControll:動作Stream管理類,這里主要是用于監(jiān)聽它的變化來完成對計數(shù)管理的動作; -
incrementCounter:動作寫入;
工作流程很清晰,也就是當對incrementCounter寫入的時候,其監(jiān)聽事件_handleLogic(data)觸發(fā),計數(shù)增加1,然后dispose()方法則將兩個Stream管理類進行關閉;
2.如何去使用
使用StreamBuilder<T>包裹需要動態(tài)顯示的控件進行使用:
StreamBuilder<int>(
stream: bloc.outCounter,
initialData: bloc._counter,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text('now index is ${snapshot.data}');
},
)
當然需要實例化一個狀態(tài)管理類:
final IncrementBloc bloc = IncrementBloc();
接下來只需要對bloc進行操作就可以了:
bloc.incrementCounter.add(null);
Demo:
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final IncrementBloc bloc = IncrementBloc();
return new Scaffold(
appBar: AppBar(
title: Text('bLoc test page'),
),
body: Center(
child: StreamBuilder<int>(
stream: bloc.outCounter,
initialData: bloc._counter,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text('now index is ${snapshot.data}');
},
),
),
floatingActionButton: new FloatingActionButton(
backgroundColor: Colors.blue,
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () {
bloc.incrementCounter.add(null);
},
),
);
}
}
當點擊FAB的時候,就會將計數(shù)管理+1,然后居中文字動態(tài)顯示,避免了StatefulWidget中動輒全部刷新的情況;
但是當我們用這種方法使用StatelessWidget來替代StatefulWidget的時候,并沒有類似dispose的方法來讓我們執(zhí)行Stream關閉的操作:
所以要么就使用StatefulWidget來實現(xiàn),但是并不使用其setState方法來全部刷新;
3.使用StatefulWidget封裝
class BlocProvider<T extends BlocBase> extends StatefulWidget {
final T bloc;
final Widget child;
BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}) : super(key: key);
@override
_BlocProviderState createState() => new _BlocProviderState();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState extends State<BlocProvider<BlocBase>> {
@override
Widget build(BuildContext context) {
return widget.child;
}
@override
void dispose() {
// TODO: implement dispose
widget.bloc.dispose();
super.dispose();
}
}
使用:
IncrementBloc bloc = new IncrementBloc();
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return BlocProvider<IncrementBloc>(
child: CounterPage(),
bloc: bloc);
}),
);
這樣的話,BlocProvider在退出銷毀dispose的時候,就會自動調用狀態(tài)管理中實現(xiàn)的銷毀dispose方法了,當然這明顯是一個局部狀態(tài)管理;
全局狀態(tài)管理的話,在runApp()處實現(xiàn)一個就行了。