Flutter StreamBuilder源码分析

作者: i校长 | 来源:发表于2020-03-28 11:17 被阅读0次

    您好

    经过一段时间的接触,和项目的不断迭代,不得不用一些手段来控制Widget的状态,对于大多数刚接触Flutter的人,知道如何更新Flutter组件的方式无非就是setState,还在某些论坛或者官网上看到InheritedWidget这个东东,那他们是如何更新的UI呢?这期我们不谈InheritedWidget,但当我点进去StreamBuilder里看到它继承自StatefulWidget时,我T..惊了,难道StreamBuilder也是setState?所以接下来,我们一探究竟。

    StreamBuilder 源码

    class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> {
      /// [stream] 与指定[Streams]的交互快照,
      ///  [builder] 必须传,构建UI
      /// [initialData] 初始化数据时用
      /// 创建StreamBuilder对象
      const StreamBuilder({
        Key key,
        this.initialData,
        Stream<T> stream,
        @required this.builder,
      }) : assert(builder != null),
           super(key: key, stream: stream);
    
      /// 为当前对象创建一个异步策略的builder
      final AsyncWidgetBuilder<T> builder;
    
      /// 抽象这个主要是因为数据是异步的,
      /// 需要一个初始值用于显示。
      final T initialData;
    
      @override
      AsyncSnapshot<T> initial() => AsyncSnapshot<T>.withData(ConnectionState.none, initialData);
    
      @override
      AsyncSnapshot<T> afterConnected(AsyncSnapshot<T> current) => current.inState(ConnectionState.waiting);
    
      @override
      AsyncSnapshot<T> afterData(AsyncSnapshot<T> current, T data) {
        return AsyncSnapshot<T>.withData(ConnectionState.active, data);
      }
    
      @override
      AsyncSnapshot<T> afterError(AsyncSnapshot<T> current, Object error) {
        return AsyncSnapshot<T>.withError(ConnectionState.active, error);
      }
    
      @override
      AsyncSnapshot<T> afterDone(AsyncSnapshot<T> current) => current.inState(ConnectionState.done);
    
      @override
      AsyncSnapshot<T> afterDisconnected(AsyncSnapshot<T> current) => current.inState(ConnectionState.none);
    
      @override
      Widget build(BuildContext context, AsyncSnapshot<T> currentSummary) => builder(context, currentSummary);
    }
    

    这里观察到四个关键的类

    • StreamBuilderBase<T, AsyncSnapshot<T>>
    • AsyncWidgetBuilder<T>
    • AsyncSnapshot<T>
    • Stream<T>
      都是什么鬼,我也不知道,我们往下看,接下来一个个分析下

    StreamBuilderBase<T, AsyncSnapshot<T>>

    StreamBuilder的基类,StreamBuilderBase使用了泛型

    • T 就是我们定义的数据类型
    • S 从上面可以看到它的实现是AsyncSnapshot<T>,为什么用AsyncSnapshot包一层呢,一会我们看下AsyncSnapshot到底是干嘛的就明白了。接着往下看,可以直接看源码注释:
    abstract class StreamBuilderBase<T, S> extends StatefulWidget {
      /// 构造函数,主要接收Stream流
      const StreamBuilderBase({ Key key, this.stream }) : super(key: key);
    
      /// 这里需要注意的是,有可能为空,因为我们有可能不传,我有个疑问,如果不传的话,UI处理什么呢?
      final Stream<T> stream;
    
       /// 我们结合子类的实现 
       /// AsyncSnapshot<T>.withData(ConnectionState.none, initialData)
       /// 返回了AsyncSnapshot的函数withData,并设置当前的AsyncSnapshot快照的状态为ConnectionState.none,并传入我们的初始化数据initialData
      S initial();
    
      /// 返回 current.inState(ConnectionState.waiting),改状态为waiting
      S afterConnected(S current) => current;
    
      /// 返回 AsyncSnapshot<T>.withData(ConnectionState.active, data)
      /// 改变连接状态active,并更新数据data
      S afterData(S current, T data);
    
      /// 返回 AsyncSnapshot<T>.withError(ConnectionState.active, error);
      /// 通知前端有错误
      S afterError(S current, Object error) => current;
    
      /// 返回current.inState(ConnectionState.done),改变状态done
      S afterDone(S current) => current;
    
      /// current.inState(ConnectionState.none) ,改变状态none
      S afterDisconnected(S current) => current;
    
      /// 返回 builder(context, currentSummary) 
      /// 其实这里就是我们实现的builder代码
      Widget build(BuildContext context, S currentSummary);
    
      @override
      State<StreamBuilderBase<T, S>> createState() => _StreamBuilderBaseState<T, S>();
    }
    

    这里发现都是一些抽象函数,被StreamBuilder都逐个实现了,目的很清晰,抽象的函数都是对AsyncSnapshot<T>的操作,从初始化到更新再到断开。不难猜出,其实AsyncSnapshot就是对我们传入的数据T的一个包装类,用来记录并控制数据的状态,角色类似我们网络请求中BaseResponse<T>的存在,是不是很像。接下来到重点了,来看看StreamBuilder如何操作的AsyncSnapshot。来看下代码

    _StreamBuilderBaseState类

    大致流程:
    在 initState 、didUpdateWidget 中会调用 _subscribe 方法,从而调用 Stream 的 listen,然后通过 setState 更新UI

    /// State for [StreamBuilderBase].
    class _StreamBuilderBaseState<T, S> extends State<StreamBuilderBase<T, S>> {
      StreamSubscription<T> _subscription;
      S _summary;
    
      @override
      void initState() {
        super.initState();
        _summary = widget.initial();
        _subscribe();
      }
    
      @override
      void didUpdateWidget(StreamBuilderBase<T, S> oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (oldWidget.stream != widget.stream) {
          if (_subscription != null) {
            _unsubscribe();
            _summary = widget.afterDisconnected(_summary);
          }
          _subscribe();
        }
      }
    
      @override
      Widget build(BuildContext context) => widget.build(context, _summary);
    
      @override
      void dispose() {
        _unsubscribe();
        super.dispose();
      }
    
      void _subscribe() {
        if (widget.stream != null) {
          _subscription = widget.stream.listen((T data) {
            setState(() {
              _summary = widget.afterData(_summary, data);
            });
          }, onError: (Object error) {
            setState(() {
              _summary = widget.afterError(_summary, error);
            });
          }, onDone: () {
            setState(() {
              _summary = widget.afterDone(_summary);
            });
          });
          _summary = widget.afterConnected(_summary);
        }
      }
    
      void _unsubscribe() {
        if (_subscription != null) {
          _subscription.cancel();
          _subscription = null;
        }
      }
    }
    

    这里又出现了一个新角色 StreamSubscription ,请看_subscribe函数就知道是个什么了,

    _subscription = widget.stream.listen
    

    它就是Stream流的订阅者 Subscription,嗯,到这里我也明白了,Stream是一个观察者,而流里面的数据就是通过listen函数添加一个监听,
    当Stream里的数据发生相应的变化,然后通知_subscription订阅者。
    我们再往下看,

    _subscription = widget.stream.listen((T data) {
            setState(() {
              _summary = widget.afterData(_summary, data);
            });
          }, onError: (Object error) {
            setState(() {
              _summary = widget.afterError(_summary, error);
            });
          }, onDone: () {
            setState(() {
              _summary = widget.afterDone(_summary);
            });
          });
          _summary = widget.afterConnected(_summary);
        }
    

    看到了吧,setState出现了,还真是,我擦。这里根据Stream流的实现去调用StreamBuilder中实现的afterData,afterError,afterDone等函数。
    分析完StreamBuilderBase,发现不用往下分析了,因为全清晰了,那我们来总结一下

    总结

    StreamBuilder其实就是包装了Stream流、还有对数据T包装的AsyncSnapshot快照,在Statefulwiget合适的生命周期,初始化,绑定Stream流的监听,并在生命结束的时候自动解绑,Stream流是一个生产者消费者模型,但数据是通过观察者模式通知的,最关键的是数据还是通过setState更新。
    总结几点:

    • StreamBuilder 并没有什么实质性的性能提升
    • StreamBuilder 也是一个Statefulwidget,等于是增加了一层嵌套。
    • StreamBuilder 很像是VM的角色,建议使用,一个简单的MVVM架构就这么实现了。

    相关文章

      网友评论

        本文标题:Flutter StreamBuilder源码分析

        本文链接:https://www.haomeiwen.com/subject/ipcjuhtx.html