The preface

In flutter development, we use the Bloc framework for responsive development based on state changes. In this paper, Xiaohong disassembles and simplifies Bloc’s core business block, and talks about its realization idea. Bloc’s core capabilities are divided into the following two points:

  • Add eventevent, convert ‘event stream’ to ‘state stream’state
  • Listening to theblocEvery time flow,stateStatus change, notificationwidgetupdate

Below, the method of defining Bloc is used to explain the construction of Bloc

1. Event Flow > State Flow (transit)

First, let’s simplify the Bloc code, and let’s see how Bloc converts a stream of events into a stream of states. The simplified code is as follows:

import 'dart:async';
abstract class ACubit<State> {
  StreamController<State> _controller = StreamController<State>.broadcast();
  State _state;
  State get state => _state;

  ACubit(this._state);

  ///Sends the State State to the stream
  void emit(State state) {
    if (_controller.isClosed) return;
    if (state == _state) return;
    _state = state;
    _controller.add(_state);
  }

  ///Provides method external listening State
  StreamSubscription<State> listen(
    void Function(State state) onData, {
    Function onError,
    void Function() onDone,
    bool cancelOnError,
  }) {
    return _controller.stream.listen(
      onData,
      onError: onError,
      onDone: onDone,
      cancelOnError: cancelOnError,
    );
  }

  Future<void> close() {
    return_controller.close(); }}Copy the code

ACubit provides the most basic capabilities. Provide a listen method to externally listen for ‘State’ changes; The EMIT method is used to respond to state state changes.

abstract class ABloc<Event.State> extends ACubit<State> {
  final _eventController = StreamController<Event>.broadcast();

  ABloc(State initState) : super(initState) {
    _bindEventToState();
  }

  ///Send the event
  void add(Event event) {
    if (_eventController.isClosed) return;
    _eventController.add(event);
  }

  ///Need upper level implementation (convert event to state)
  Stream<State> mapEventToState(Event event);

  ///Convert a stream of events to a stream of states
  _bindEventToState() {
    _eventController.stream
        // asyncExpand Casts the stream content, resulting in a stream
        .asyncExpand((event) => mapEventToState(event))
        .listen((nextState) {
      ///The nextState is compared with the current state. After the comparison is successful, the nextState is put into the streamemit(nextState); }); }}Copy the code

ABloc is the base class we use directly. _bindEventToState is called in the constructor to convert the event stream to the state stream.

2. How to use BlocBuilder to monitor status changes in real time?

Xiaohong made a simplified explanation of the principle:

import 'package:flutter/material.dart';
import 'a_bloc.dart';

class BlocBuilder<T extends ACubit<S>, S> extends StatefulWidget {
  final T cubit;
  final Widget Function(BuildContext context, S state) builder;

  const BlocBuilder({
    Key key,
    @required this.cubit,
    @required this.builder,
  }) : super(key: key);

  @override
  _BlocBuilderState<S> createState() => _BlocBuilderState<S>();
}

class _BlocBuilderState<S> extends State<BlocBuilder> {
  void _update() {
    setState(() {});
  }

  @override
  void initState() {
    ///Listen for state changeswidget.cubit? .listen((_) { _update(); });super.initState();
  }

  @override
  voiddispose() { widget.cubit? .close();super.dispose();
  }

  @override
  Widget build(BuildContext context){
    returnwidget.builder( context, widget.cubit.state, ); }}Copy the code

Encapsulation BlocBuilder

  • The constructor passes in a custom bloc (inheritanceABloc),builderPass parameter is used to get each timestateNotice of change.
  • ininitStateInit methodcubitState listening, called directly for each state changesetStateMethod to update the page

The following is an example of a call:

return BlocBuilder<CountBloc, CountState>(
      cubit: CountBloc(CountState(1)),
      builder: (context, state) {
       returnContainer(... Omit business code)},)Copy the code

conclusion

Tripartite libraries such as Provider are referenced in BLOC library. Data sharing capabilities are implemented based on InheritedWidget. In this article, we only demonstrate the processing idea of Bloc core. Refer to Bloc source for details.


extension

The InheritedProvider implements data sharing Bloc simultaneously add twice and only responds to one problem processing