BLoC 全称是Business Logic Component,业务逻辑组件,简称 Bloc。
1、Stream实现Bloc
1.Bloc 的实现
counter_bloc 类
import 'dart:async';
class CounterBLoC{
//记录按钮点击的次数
//被流包裹的数据(可以是任何类型)
int _counter =0;
//流控制
final _counterStreamController =new StreamController<int>();
//流
Stream<int> get stream_counter=> _counterStreamController.stream;
// 通过sink.add发布一个流事件
void addCount(){
_counterStreamController.sink.add(++_counter);
}
//释放流
void dispose(){
_counterStreamController.close();
}
}
2.BLoC 的使用
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'counter_bloc.dart';
class CountPage extends StatefulWidget {
@override
_CountPageState createState() => _CountPageState();
}
class _CountPageState extends State<CountPage> {
//把一些相关的数据请求,实体类变换抽到CounterBLoC这个类里
//实例化CounterBLoC
final _bloc = new CounterBLoC();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("CountBloc"),),
body: StreamBuilder(
//监听流,当流中的数据发生变化(调用过sink.add时,此处会接收到数据的变化并且刷新UI)
stream: _bloc.stream_counter,
initialData: 0,
builder: (BuildContext context,AsyncSnapshot<int> snapshot){
return Center(
child: Text(snapshot.data.toString(),style: TextStyle(fontSize: 40,fontWeight: FontWeight.w300),),
);
},
),
floatingActionButton: _getButton(),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//关闭流
_bloc.dispose();
}
Widget _getButton(){
return FloatingActionButton(child: Icon(Icons.add),
onPressed: (){
// 点击添加;其实也是发布一个流事件
_bloc.addCount();
});
}
}
示例源码
https://github.com/anymyna/flutter-examples/tree/master/flutter_app_bloc_counter
2、RxDart实现Bloc
1.网络请求NetApi 类
import 'dart:convert';
import 'package:http/http.dart' show Client;
import 'beauty_model.dart';
class NetApi {
Client client = new Client();
Future<List<BeautyModel>> fetchBeauties() async {
print("Starting get beauties ..");
List models = List();
final response =
await client.get("http://gank.io/api/data/福利/15/1");
if (response.statusCode == 200) {
models = json.decode(response.body)["results"];
return models.map((model){
return BeautyModel.fromJson(model);
}).toList();
} else {
throw Exception('Failed to load dog');
}
}
}
2.BLoC 类的实现
import 'package:rxdart/rxdart.dart';
import '../bloc_provider.dart';
import 'beauty_model.dart';
import 'net_api.dart';
class BeautyBloc {
//网络请求的实例
NetApi _netApi =new NetApi();
final _beautyFetcher = PublishSubject<List<BeautyModel>>();
//提供被观察的List<BeautyModel
Observable<List<BeautyModel>> get beauties =>_beautyFetcher.stream;
//获取网络数据
fetchBeauties() async{
List models = await _netApi.fetchBeauties();
if(_beautyFetcher.isClosed)return;
_beautyFetcher.sink.add(models);
}
//释放
dispose(){
_beautyFetcher?.close();
}
}
3.BLoC 的使用
import 'package:flutter/material.dart';
import 'beauty_bloc.dart';
import 'beauty_model.dart';
class BeautyPage extends StatefulWidget {
@override
_BeautyPageState createState() => _BeautyPageState();
}
class _BeautyPageState extends State<BeautyPage> {
final _beautyBloc = BeautyBloc();
@override
void initState() {
// TODO: implement initState
super.initState();
_beautyBloc.fetchBeauties();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("BeautyPage"),
),
body: Container(
child: StreamBuilder(
//监听流
stream: _beautyBloc.beauties,
builder: (context, AsyncSnapshot<List<BeautyModel>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Image.network(
snapshot.data[index].url,
fit: BoxFit.fill,
));
},
itemCount: snapshot.data.length,
);
} else if (snapshot.hasError) {
return Text('Beauty snapshot error!');
}
return Text('Loading Beauties..');
})),
);
}
}
示例源码
https://github.com/anymyna/flutter-examples/tree/master/flutter_app_bloc_rxdart
3、Bloc封装展示
1.BlocProvider
import 'package:flutter/material.dart';
import 'beauty_bloc_example/net_api.dart';
//获类型
Type _typeOf<T>() {
return T;
}
abstract class BlocBase {
//一些网络接口API
NetApi netApi = new NetApi();
//释放
void dispose();
}
//更方便的管理Bloc
class BlocProvider<T extends BlocBase> extends StatefulWidget {
final T bloc; //bloc
final Widget child; //子Widget
//构造
const BlocProvider({Key key,@required this.bloc, @required this.child}) : super(key: key);
//通过ancestorInheritedElementForWidgetOfExactType获取
//bloc 实例
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<_BlocProviderInherited<T>>();
_BlocProviderInherited<T> provider =
context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
return provider?.bloc;
}
@override
_BlocProviderState<T> createState() {
// TODO: implement createState
return _BlocProviderState();
}
}
class _BlocProviderState<T extends BlocBase>
extends State<BlocProvider<BlocBase>> {
@override
/// 便于资源的释放
void dispose() {
widget.bloc?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return new _BlocProviderInherited<T>(
child: widget.child,
bloc: widget.bloc,
);
}
}
class _BlocProviderInherited<T> extends InheritedWidget {
_BlocProviderInherited({
Key key,
@required Widget child,
@required this.bloc,
}) : super(key: key, child: child);
final T bloc;
@override
bool updateShouldNotify(_BlocProviderInherited oldWidget) => false;
}
2.BeautyBasePage 类
import 'package:flutter/material.dart';
import 'package:flutter_bloc_example/bloc_provider.dart';
import 'beauty_base_bloc.dart';
import 'beauty_bloc.dart';
import 'beauty_model.dart';
class BeautyBasePage extends StatefulWidget {
@override
_BeautyBasePageState createState() => _BeautyBasePageState();
}
class _BeautyBasePageState extends State<BeautyBasePage> {
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
//拿到 BeautyBaseBloc 实例
BeautyBaseBloc _bloc= BlocProvider.of<BeautyBaseBloc>(context);
//获取网络数据
_bloc.fetchBeauties();
return Scaffold(
appBar: AppBar(
title: Text("BeautyPage"),
),
body: Container(
child: StreamBuilder(
stream: _bloc.beauties,
builder: (context, AsyncSnapshot<List<BeautyModel>> snapshot) {
if (snapshot.hasData) {
print('has data');
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Image.network(
snapshot.data[index].url,
fit: BoxFit.fill,
));
},
itemCount: snapshot.data.length,
);
} else if (snapshot.hasError) {
return Text('Beauty snapshot error!');
}
return Text('Loading Beauty..');
})),
);
}
}
- BlocProvider使用
class BeautyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "BeautyBloc Demo",
theme: new ThemeData(
primarySwatch: Colors.blue,
),
//插入 BlocProvider
home: BlocProvider<BeautyBaseBloc>(
child: BeautyBasePage(), bloc: new BeautyBaseBloc()),
);
}
}
示例源码
https://github.com/anymyna/flutter-examples/tree/master/flutter_app_bloc_collect
4、Bloc开源组件
1.添加依赖:
dependencies:
bloc: ^0.15.0
flutter_bloc: ^0.21.0
- CounterBloc 依赖bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
@override
CounterState get initialState => CounterLoading(0);
@override
Stream<CounterState> mapEventToState(
CounterEvent event,
) async* {
if(event is CounterLoad) {
yield* _mapCounterLoadToState();
} else if (event is CounterIncrease) {
yield* _mapCounterIncreaseToState(event);
} else if (event is CounterDecrease) {
yield* _mapCounterDecreaseToState(event);
}
}
Stream<CounterState> _mapCounterLoadToState() async* {
try {
yield CounterLoaded(0);
} catch (_) {
yield CounterUnLoaded(0);
}
}
Stream<CounterState> _mapCounterIncreaseToState(CounterEvent counterEvent) async* {
if (currentState is CounterLoaded) {
final int counter = (currentState as CounterLoaded).counter + counterEvent.counter;
yield CounterLoaded(counter);
_print(counter);
}
}
Stream<CounterState> _mapCounterDecreaseToState(CounterEvent counterEvent) async* {
if (currentState is CounterLoaded) {
final int counter = (currentState as CounterLoaded).counter - counterEvent.counter;
yield CounterLoaded(counter);
_print(counter);
}
}
void _print(int counter) {
print(counter);
}
}
- BlocBuilder 依赖flutter_bloc
class _SecondPageState extends State<SecondPage> {
@override
Widget build(BuildContext context) {
final counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(
leading: GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(Icons.arrow_back),
),
title: Text('Second Page'),
),
body: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${state.counter}',
style: Theme.of(context).textTheme.display1,
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {counterBloc.dispatch(CounterIncrease(1));},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
示例源码
https://github.com/anymyna/flutter-examples/tree/master/flutter_app_bloc_demo