flutter_bloc使用及部分源码分析

flutter_bloc 是一个bloc第三方库,这个库很方便的让你集成bloc模式,这个库结合了RXDart。目前我们项目中就有用到rxdart。

bloc模式

BLoC是一种利用reactive programming方式构建应用的方法,这是一个由流构成的完全异步的世界。

常用的概念简介

  • reactive programming: 响应式编程 , 一种基于事件模式的模型。

  • Stream:流是一系列异步的数据.。

  • Observable实现并扩展了Stream。它将常用的stream和streamTransformer组合成了非常好用的api。你可以把它当成stream。

  • streamController:可以使用rxdart中的subjec替代streamController,subject可以视为streamController的增强版。根据数据流监听器个数的不同,Stream数据流可以分为单订阅流和多订阅流。

  • Subject:实现并扩展了StreamController,它符合StreamController的所有规范。假如之前使用的是StreamController,那么你可以直接替换为Subject。

  • StreamBuilder:包裹有状态的部件,streambuilder将会监听一个来自于BLoC的流,监听到新的数据,产生一个新的snapshot,并重新调用builder方法,Widget被重新构建。

工作流程图:

在这里插入图片描述

通过 StreamController 的 sink来添加数据,然后通过 StreamController 发送给 Stream,而订阅者则通过调用Stream的listen()方法来进行监听,listen()方法会返回一个 StreamSubscription 对象,StreamSubscription 对象支持对数据流进行暂停、恢复和取消等操作。

扫描二维码关注公众号,回复: 16051810 查看本文章

BLoC模式优点

相比传统的setState方式,StreamBuilder是一个很大的进步,因为它不需要强行重建整个组件树和它的子组件,只需要重建StreamBuilder包裹的组件即可.

  • Cubit : 是 Stream 的一种特殊类型,用作 Bloc 类的基础,一个 Cubit 可以公开触发状态变化的函数。
  • BlocProvider: Flutter小部件,可通过BlocProvider.of<T>(context)为其子级提供一个cubit。它用作依赖项注入widget,以便可以将子位的单个实例提供给子树中的多个小部件。
BlocProvider({
    Key key,
  	//创建一个Cubit的实例
    @required Create<T> create,
    Widget child,
  //默认情况下,BlocProvider将懒惰地创建cubit,这意味着当通过BlocProvider.of <BlocA>(上下文)查找cubit时,将执行创建。
    bool lazy,
  }) : this._(
          key: key,
          create: create,
          dispose: (_, bloc) => bloc?.close(),
          child: child,
          lazy: lazy,
        );
  • BlocBuilder : BlocBuilder是一个Flutter小部件,它需要一个cubit和一个builder函数。 BlocBuilder处理构建小部件以响应新状态。 BlocBuilder与StreamBuilder非常相似,但具有更简单的API以减少所需的样板代码量。可能会多次调用builder函数,并且应该是一个纯粹的函数,该函数会根据状态返回小部件。与StreamBuilder的作用一样,但是它简化了StreamBuilder的实现细节,减少一部分必须的模版代码
 const BlocBuilder({
    Key key,
    @required this.builder,
   //如果省略cubit参数,则BlocBuilder将使用BlocProvider和当前的BuildContext自动执行查找。
    C cubit,
   //根据返回 true/false 来决定是否更新页面
    BlocBuilderCondition<S> buildWhen,
  })  : assert(builder != null),
        super(key: key, cubit: cubit, buildWhen: buildWhen);


typedef BlocBuilderCondition<S> = bool Function(S previous, S current);
  • MultiBlocProvider是Flutter小部件,将多个BlocProvider小部件合并为一个。 MultiBlocProvider提高了可读性,并且无需嵌套多个BlocProvider。
  • BlocListener是一种Flutter小部件,它接受BlocWidgetListener和一个可选的cubit,并响应于cubit中的状态更改而调用侦听器。它应用于每次状态更改都需要发生一次的功能,例如导航,显示SnackBar,显示对话框等。仅当您希望提供无法通过BlocProvider和当前BuildContext访问的cubit时,才指定cubit。 (看源码得知,BlocBuilder内部就是封装了BlocListener)
BlocListener<BlocA, BlocAState>(
  cubit: blocA,
  listener: (context, state) {
   //根据BlocA的中的值在此处进行操作,比如想弹个窗
  }
)

可以在Android Studio看一个简单的示例。

获取cubit实例的方法有两种,一种是关注更新,一种是不关注更新:

  1. 不关注
// with extensions
context.read<BlocA>();

// without extensions
BlocProvider.of<BlocA>(context);

比如下图中的两个按钮:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t2Yh366o-1611042317793)(https://i.loli.net/2021/01/18/7jGlTcsA6zxVm4g.png)]

他俩是不需要进行重绘的,无论数值怎么变化,这两个按钮的UI是不需要更改的,那么此时获取cubit就可以使用上面的方法。

  1. 关注

    // with extensions
    context.watch<BlocA>();
    
    // without extensions
    BlocProvider.of<BlocA>(context, listen: true);
    
  2. 满足一定条件时更改

final isPositive = context.select((CounterBloc b) => b.state > 0);

如果CounterBloc的状态从正负之前切换,以上代码段才会重建。

Cubit

Cubit是 Stream 的一种特殊类型,用作 Bloc 类的基础 . 一个 Cubit 可以公开触发状态变化的函数。

状态是从 Cubit 中输出的,代表应用程序状态的一部分。可以通知UI组件状态,并根据当前状态重绘其自身的某些部分

创建 Cubit 时,我们需要定义 Cubit 将要管理的状态类型。对于上面的 CounterCubit,状态可以通过 int 来表示,但在更复杂的情况下,可能有必要使用 class(类)而不是原始类型。

class CounterCubit extends Cubit<int> {
  CounterCubit(int initialState) : super(initialState);
  void increment() => emit(state + 1);
}

每个 Cubit 都有能力通过 emit 输出一个新状态.

在上面的代码片段中,CounterCubit 公开了一个名为 increment 的公共方法,可以从外部调用该方法,以通知CounterCubit 增加其状态。当调用 increment 时,我们可以通过 state 获取器访问 Cubit 的当前状态,并通过向当前状态加 1 来发出 emit 新状态。

emit 函数受到保护,这意味着它只能在 Cubit 内部使用。

源码分析

//因为是 abstract , 所以我们可以重写它的方法来扩展实现想要的功能
abstract class Cubit<State> extends Stream<State> {
  Cubit(this._state) {
    _observer.onCreate(this);
  }

  State get state => _state;

  BlocObserver get _observer => Bloc.observer;

  StreamController<State> _controller;

  State _state;

  bool _emitted = false;

  @protected
  @visibleForTesting
  void emit(State state) {
    //初始化_controller  多订阅
    _controller ??= StreamController<State>.broadcast();
    
    //如果[Cubit]已关闭或发出的[state]等于当前[state],则[emit]不执行任何操作。
    if (_controller.isClosed) return;
    if (state == _state && _emitted) return;
    onChange(Change<State>(currentState: this.state, nextState: state));
    //将[状态]更新为提供的[状态]。
    _state = state;
    _controller.add(_state);
    _emitted = true;
  }

  ///通知[Cubit]触发[onError]的[错误]。
  void addError(Object error, [StackTrace stackTrace]) {
    onError(error, stackTrace);
  }

 	///给定的[change]发生[change]时调用。
  ///当发出一个新的“状态”时发生[变化]。在更新“ cubit”的“ state”之前调用[onChange]。 [onChange]是为特定“cubit”添加日志记录分析的好地方
  @mustCallSuper
  void onChange(Change<State> change) {
    // ignore: invalid_use_of_protected_member
    _observer.onChange(this, change);
  }

  /// 每当[Cubit]中发生[错误]时调用。
  /// 默认情况下,所有[错误]都将被忽略,并且[Cubit]功能将不受影响。
  ///一个在[Cubit]级别处理错误的好地方。
  @protected
  @mustCallSuper
  void onError(Object error, StackTrace stackTrace) {
    // ignore: invalid_use_of_protected_member
    _observer.onError(this, error, stackTrace);
    assert(() {
      throw CubitUnhandledErrorException(this, error, stackTrace);
    }());
  }

  /// 将订阅添加到Stream<State>中.
  /// 返回一个[StreamSubscription],它使用提供的[onData],[onError]和[onDone]处理程序处理Stream <State>中的事件。
  @override
  StreamSubscription<State> listen(
    void Function(State) onData, {
    Function onError,
    void Function() onDone,
    bool cancelOnError,
  }) {
    _controller ??= StreamController<State>.broadcast();
    return _controller.stream.listen(
      onData,
      onError: onError,
      onDone: onDone,
      cancelOnError: cancelOnError,
    );
  }

  @override
  bool get isBroadcast => true;

  ///关闭[Cubit]。
  ///当调用close时,将不再发出新状态。
  @mustCallSuper
  Future<void> close() {
    _observer.onClose(this);
    _controller ??= StreamController<State>.broadcast();
    return _controller.close();
  }
}

BlocListener

class _BlocListenerBaseState<C extends Cubit<S>, S>
    extends SingleChildState<BlocListenerBase<C, S>> {
  StreamSubscription<S> _subscription;
  S _previousState;
  C _cubit;

  @override
  void initState() {
    super.initState();
    _cubit = widget.cubit ?? context.read<C>();
    _previousState = _cubit.state;
    _subscribe();
  }

  @override
  void didUpdateWidget(BlocListenerBase<C, S> oldWidget) {
    super.didUpdateWidget(oldWidget);
    final oldCubit = oldWidget.cubit ?? context.read<C>();
    final currentCubit = widget.cubit ?? oldCubit;
    if (oldCubit != currentCubit) {
      if (_subscription != null) {
        _unsubscribe();
        _cubit = currentCubit;
        _previousState = _cubit.state;
      }
      _subscribe();
    }
  }

  @override
  Widget buildWithChild(BuildContext context, Widget child) => child;

  @override
  void dispose() {
    _unsubscribe();
    super.dispose();
  }

  void _subscribe() {
    if (_cubit != null) {
      _subscription = _cubit.listen((state) {
        if (widget.listenWhen?.call(_previousState, state) ?? true) {
          widget.listener(context, state);
        }
        _previousState = state;
      });
    }
  }

  void _unsubscribe() {
    if (_subscription != null) {
      _subscription.cancel();
      _subscription = null;
    }
  }
}

示例项目地址

猜你喜欢

转载自blog.csdn.net/u011272795/article/details/112842510