BLoC
BLoC表示为业务逻辑组件 (Business Logic Component),由谷歌在2018的 DartConf 首次提出------其诞生可以说是为了解耦。
在了解该框架之前需要了解;
//建一个类ApplicationBloc -------- 记住这个类名字
BehaviorSubject _appEvent = BehaviorSubject(); //该BehaviorSubject也是广播 StreamController,它返回一个Observable,而不是Stream。
Sink get _appEventSink => _appEvent.sink; //Widgets 通过 Sinks 向 BLoC 发送事件(event)
Stream get appEventStream => _appEvent.stream; //BLoC 通过流(stream)通知小部件(widgets)
(BehaviorSubject,不知道啥的向下看)
StreamController control= StreamController();
//监听StreamController 的stream属性,就可以时刻关注到传递的内容
StreamSubscription subscription = control.stream.listen((data) => print('$data'));
control.sink.add(6666);
control.close();
上述是Stream单订阅的一种表现方式。那么再看看另外一种形态 ----- 广播流。
StreamController ctrl = StreamController.broadcast();
StreamSubscription subscription = ctrl.stream
.where((value) => (value % 2 == 0))
.listen((value) => print('$value'));
for(int i=1; i<11; i++){
ctrl.sink.add(i);
}
//一般在dispose方法中close掉
ctrl.close();
另外一个关键词,StreamTransformer ---- 控制Stream内部数据的处理。
StreamTransformer可以用进行任何类型的处理,例如:
过滤(filtering):根据任何类型的条件过滤数据,
重新组合(regrouping):重新组合数据,
修改(modification):对数据应用任何类型的修改,
将数据注入其他流,
缓冲,
处理(processing):根据数据进行任何类型的操作/操作,
…
即把流转换为流。
RxDart
简单来说,RxDart 扩展了原始的Dart Streams API并提供了StreamController的 3个主要变体:PublishSubject、BehaviorSubject、ReplaySubject涵盖着事件订阅的概念,三者返回的都是Observable
反应式编程
反应式编程是使用异步数据流进行编程,换句话说一个事件由数据流触发时,其连带的所有内容都会被传送,即让整个行为变得异步。
看到这里,结合1中ApplicationBloc那里注册的BehaviorSubject广播,我们可以在需要发送广播的地方:
//在ApplicationBloc 中添加该方法
void sendAppEvent(int type) {
_appEventSink.add(type);
}
//在build中初始化
final ApplicationBloc bloc = BlocProvider.of(context);
//需要调用的地方进行调用
bloc.sendAppEvent(Constant.TYPE_SYS_UPDATE);
//在接收的地方
BlocProvider(
bloc: ApplicationBloc(),
child: BlocProvider(child: XX(), bloc: null),
)
其中的BlocProvider,现在通用写法是
import 'dart:async';
import 'package:flutter/material.dart';
abstract class BlocBase {
Future getData({String labelId, int page});
Future onRefresh({String labelId});
Future onLoadMore({String labelId});
void dispose();
}
Type _typeOf() => T;
class BlocProvider extends StatefulWidget {
BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}): super(key: key);
final Widget child;
final T bloc;
@override
_BlocProviderState createState() => _BlocProviderState();
static T of(BuildContext context){
final type = _typeOf<_BlocProviderInherited>();
_BlocProviderInherited provider =
context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
return provider?.bloc;
}
}
class _BlocProviderState extends State>{
@override
void dispose(){
widget.bloc?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context){
return new _BlocProviderInherited(
bloc: widget.bloc,
child: widget.child,
);
}
}
//由于使用了InheritedWidget,它现在可以调用context.ancestorInheritedElementForWidgetOfExactType()函数,它是一个O(1),这意味着祖先的检索是立即的
class _BlocProviderInherited 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;
}
在这里只是简单了解下,有需要更清晰讲解的可以去看这是一个链接
除了自己学习怎么运用BLoc之外,还可以去https://pub.dartlang.org/packages/去搜索BLoc添加某人上传的依赖(还需要添加flutter_bloc
辅助运用)。后者简单了许多。举个简单的例子
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter_acesmart/entity/banner_entity.dart';
import 'package:flutter_acesmart/entity/base_entity.dart';
import 'package:flutter_acesmart/http/index.dart';
import 'package:flutter_acesmart/http/robort_index.dart';
import 'home_event.dart';
//HomeEvent和HomeState是我定义在home_event的类,HomeEvent为事件触发,HomeState为事件处理后或之前的状态。
class HomeBloc extends Bloc {
@override
HomeState get initialState => HomeBannerLoading();
//这个是必须实现的方法
@override
Stream mapEventToState(HomeEvent event) async* {
if (event is HomeBannerLoad) {
yield* mapLoadBannerToState();
}
}
Stream mapLoadBannerToState() async* {
try {
List bannerEntitys = await _getBanners();
yield HomeBannerLoaded(bannerEntitys);
//fixme:获取机器人保留的数据或者initstate中disparch
} catch (e) {
yield LoadError(e);//在HomeState中定义的错误状态方法
}
}
//不用加try-catch,调用层已捕获了
//BannerEntity是定义的mode类
Future> _getBanners() async {
Response response = await HomeApi.getBanners();
BaseEntity baseEntity = BaseEntity.fromJson(response.data);
List bannerEntitys = baseEntity.data.map((e) {
return BannerEntity.fromJson(e);
}).toList();
return bannerEntitys;
}
}
下main看看HomeEvent和HomeState(其实可以把他们放在一个类里面,我是觉得放在一起也挺好)
import 'package:equatable/equatable.dart';
import 'package:flutter_acesmart/entity/banner_entity.dart';
import 'package:meta/meta.dart';
abstract class HomeEvent extends Equatable {
HomeEvent([List props = const []]) : super(props);
}
abstract class HomeState extends Equatable {
HomeState([List props = const []]) : super(props);
}
///加载主页数据
// event
class HomeBannerLoad extends HomeEvent {
@override
String toString() {
return 'HomeBannerLoad';
}
}
//event需要传递参数时
class lampChange extends HomeEvent{
final int light;
lampChange({@required this.light})
: assert(light != null),
super([light]);
@override
String toString() {
return 'lampChange';
}
}
///State
class HomeBannerLoading extends HomeState {
@override
String toString() {
return 'HomeBannerLoading';
}
}
//banner下载完毕状态切换,同时把数据绑定传送
class HomeBannerLoaded extends HomeState {
List banners;
HomeBannerLoaded(this.banners) : super([banners]);
@override
String toString() {
return 'ProjectBannerLoaded{banners: ${banners?.length}}';
}
}
class LoadError extends HomeState {
Exception exception;
LoadError(this.exception) : super([exception]);
@override
String toString() {
return 'HomeLoadError';
}
}
在需要调用的地方
class HomePage extends StatefulWidget{
@override
State createState() {
return new HomePageState();
}
}
class HomePageState extends Statewith TickerProviderStateMixin {
HomeBloc homeBloc ;
List banners;
@override
void initState() {
super.initState();
homeBloc = HomeBloc();
banners ??= [];
//调用banner下载event
homeBloc.dispatch(HomeBannerLoad());
}
@override
Widget build(BuildContext context) {
LogUtil.e("HomePage build......");
return Center(
child: BlocListener(
bloc: homeBloc,
listener: (context, state) {
if (state is HomeBannerLoaded) {
banners = state.banners; //绑定数据
}
else if(state is LoadError) {
DisplayUtil.showMsg(context, exception: state.exception);
}
},
child: BlocBuilder(
bloc: homeBloc,
builder: (context, state) {
return Stack(
children: [
Scaffold(
.......
body: Builder(builder: (context) {
return Stack(
)
],
),
......
大致的使用流程就是这样啦。