Flutter之Bloc模式

Flutter之Bloc模式

全称Business Logic Component,业务逻辑组件

在这里插入图片描述

BLoC 是独立处理业务逻辑(网络数据请求、数据处理等等的逻辑),通过流Stream的Sinks,streams发布监听业务处理后的数据,只关心业务处理。而Widget着重业务数据处理后的结果显示。将业务逻辑和UI分离。

widget做UI展示,bloc做逻辑处理,model做数据封装

1.工作流程

组件通过Sink向Bloc发送事件,BLoC接收到事件后执行内部逻辑处理,并把处理的结果通过流的方式通知给订阅事件流的组件。在BLoC的工作流程中,Sink接受输入,BLoC则对接受的内容进行处理,最后再以流的方式输出。可以发现,BLoC又是一个典型的观察者模式。

2.使用

项目采取Bloc+RxDart来开发

2.1Bloc实现原理

Bloc触发刷新的方式是使用StreamBuilder+StreamController。

Bloc另一重要特性就是跨层级获取bloc,在bloc可以获取到model或者调用方法。

其中使用了ancestorWidgetOfExactType,因为flutter widget是树状结构的,结构层次保存在BuildContext中,可以从子节点依次往父节点找符合类型的widget,所以所有使用了BlocProvider包裹的widget都可以通过of方法找到,再返回widget中的bloc。(bloc最终是保存在外一层的state中)。

final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
2.2RxDart实现原理

StreamController实现了观察者模式,监听者不是直接被调用,而是处于观察状态,当事件加入streamController后,监听者获得异步回调。

在这里插入图片描述

RxDart是对StreamController的扩展,提供了更多的模式。分为两个部分Subject和Observable。

在这里插入图片描述

其中Observable对stream封装后提供多个处理方法,例如map、expand、merge、every、contact,可以对数据进行相应的遍历、合并等操作。

Subject是对StreamController的扩展,常用的有以下几种。

  • PublishSubject:StreamController广播版,streamController只能有一个listener,PublishSubject可以多次listen。下面的其他几种Subject也都是广播版。
  • BehaviorSubject: 缓存最近一次的事件。如果先发生事件,后listen,也能收到缓存的事件。
  • ReplaySubject: 缓存所有的事件,之前加入的所有event,listen后,都会顺序发送过来。

3.实例

1.创建一个所有Bloc的通用基类BlocBase
abstract class BlocBase{
  void dispose();
}
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<T> createState() => new _BlocProviderState<T>();

  static Type _typeOf<T>() => T;

  static T of<T extends BlocBase>(BuildContext context){
    final type = _typeOf<BlocProvider<T>>();
    BlocProvider<T> provider = context.findAncestorWidgetOfExactType();
    return provider.bloc;
  }
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
  @override
  void dispose(){
    widget.bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}
2.创建相对应的TestBloc,继承BlocBase。

Bloc 的初始化可以在任意父组件、子组件中,获取只需要使用

BlocProvider.of(context)
TestBloc  _testBloc  =  BlocProvider.of(context);
2.1定义Subject
final _subject = PublishSubject<Model>();
2.2定义Stream
Stream<Model> get stream => _subject.stream;
2.3在业务逻辑内将数据添加到_subject中,业务逻辑不局限与IO流数据、网络请求数据等
void getData(){
...数据获取方法
_suject.sink.add(data)
}

需要注意,在TestBloc中的dispose中需要调用subject(streamController)close.

@override
void dispose() {
  _subject.close();
}
2.4在widget中通过StreamBuilder来控制。
 @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return StreamBuilder(
          stream: stream,
          builder: (BuildContext context, AsyncSnapshot<Price> snapshot) {
            ...widget展示数据
		}
  }
}

可以在最顶层父组件构建UI时设置BlocProvider(),具体的UI显示封装在page()中。

 @override
  Widget build(BuildContext context) {
  return SafeArea(
      child: Scaffold(
      appBar:(AppBar...),
      body:BlocProvider(
          bloc: TestBloc(),
          child: page(),//显示的UI
        ),
      ),
    );
  }

4.综合

使用Bloc之后,数据与widget相关联,widget状态可以随数据的改变而改变。与setState()不同的是,Bloc可以局部刷新,只刷新与数据绑定的widget,不用全局刷新,setState()每次会全局刷新,提升了UI构建速度。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值