FutureBuilder源码分析

栏目: IOS · 发布时间: 4年前

内容简介:构造函数很简单,上一篇文章也说过,主要就是三个参数:其中其中
const FutureBuilder({
  Key key,
  this.future,
  this.initialData,
  @required this.builder,
}) : assert(builder != null),
super(key: key);
复制代码

构造函数很简单,上一篇文章也说过,主要就是三个参数:

  • future:是我们的异步请求, 该异步请求必须不能在 build 方法中初始化!
  • initialData:如果Future 没有完成的情况下展示该数据
  • builder:构建我们的UI

AsyncWidgetBuilder

其中 builder 的类型为 AsyncWidgetBuilder ,我们来看一下:

typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnapshot<T> snapshot);
复制代码

其中 typedef 是为函数起别名用的,

也就是说 builder 是一个方法,从而在定义builder的时候就要实现这个方法。

AsyncSnapshot

接着看一下 snapshot

@immutable
class AsyncSnapshot<T> {
  /// Creates an [AsyncSnapshot] with the specified [connectionState],
  /// and optionally either [data] or [error] (but not both).
  const AsyncSnapshot._(this.connectionState, this.data, this.error)
    : assert(connectionState != null),
      assert(!(data != null && error != null));

  /// Creates an [AsyncSnapshot] in [ConnectionState.none] with null data and error.
  const AsyncSnapshot.nothing() : this._(ConnectionState.none, null, null);

  /// Creates an [AsyncSnapshot] in the specified [state] and with the specified [data].
  const AsyncSnapshot.withData(ConnectionState state, T data) : this._(state, data, null);

  /// Creates an [AsyncSnapshot] in the specified [state] and with the specified [error].
  const AsyncSnapshot.withError(ConnectionState state, Object error) : this._(state, null, error);

  /// Current state of connection to the asynchronous computation.
  final ConnectionState connectionState;

  /// The latest data received by the asynchronous computation.
  ///
  /// If this is non-null, [hasData] will be true.
  ///
  /// If [error] is not null, this will be null. See [hasError].
  ///
  /// If the asynchronous computation has never returned a value, this may be
  /// set to an initial data value specified by the relevant widget. See
  /// [FutureBuilder.initialData] and [StreamBuilder.initialData].
  final T data;

  /// Returns latest data received, failing if there is no data.
  ///
  /// Throws [error], if [hasError]. Throws [StateError], if neither [hasData]
  /// nor [hasError].
  T get requireData {
    if (hasData)
      return data;
    if (hasError)
      throw error;
    throw StateError('Snapshot has neither data nor error');
  }

  /// The latest error object received by the asynchronous computation.
  ///
  /// If this is non-null, [hasError] will be true.
  ///
  /// If [data] is not null, this will be null.
  final Object error;

  /// Returns a snapshot like this one, but in the specified [state].
  ///
  /// The [data] and [error] fields persist unmodified, even if the new state is
  /// [ConnectionState.none].
  AsyncSnapshot<T> inState(ConnectionState state) => AsyncSnapshot<T>._(state, data, error);

  /// Returns whether this snapshot contains a non-null [data] value.
  ///
  /// This can be false even when the asynchronous computation has completed
  /// successfully, if the computation did not return a non-null value. For
  /// example, a [Future<void>] will complete with the null value even if it
  /// completes successfully.
  bool get hasData => data != null;

  /// Returns whether this snapshot contains a non-null [error] value.
  ///
  /// This is always true if the asynchronous computation's last result was
  /// failure.
  bool get hasError => error != null;

}
复制代码

前面定义了一个私有的构造函数 const AsyncSnapshot._(this.connectionState, this.data, this.error)

后面 用命名构造函数来调用私有构造函数 返回一个 snapshot。

也可以看到 hasData hasError 其实就是判断 data/error 是否等于 null。

_FutureBuilderState

重点是 _FutureBuilderState<T> ,还是从上往下看,

首先定义了两个私有变量:

/// An object that identifies the currently active callbacks. Used to avoid
/// calling setState from stale callbacks, e.g. after disposal of this state,
/// or after widget reconfiguration to a new Future.
Object _activeCallbackIdentity;
AsyncSnapshot<T> _snapshot;
复制代码

_activeCallbackIdentity 根据注释来解释大概就是: 标记当前还存活的对象,用于避免已经dispose了还调用setState。

_snapshot 就是我们刚才说用来返回数据的。

initState()

接着是初始化方法:

@override
void initState() {
  super.initState();
  _snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
  _subscribe();
}
复制代码

首先根据传入的 initialData 初始化_snapshot,

然后调用 _subscribe()

_subscribe()

看一下 _subscribe() 方法 :

void _subscribe() {
  if (widget.future != null) {
    final Object callbackIdentity = Object();
    _activeCallbackIdentity = callbackIdentity;
    widget.future.then<void>((T data) {
      if (_activeCallbackIdentity == callbackIdentity) {
        setState(() {
          _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data);
        });
      }
    }, onError: (Object error) {
      if (_activeCallbackIdentity == callbackIdentity) {
        setState(() {
          _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error);
        });
      }
    });
    _snapshot = _snapshot.inState(ConnectionState.waiting);
  }
}
复制代码

这里做了如下几件事:

  1. 判断 future 是否为null;

  2. 如果不为null,则初始化 _activeCallbackIdentity 为 Object();

  3. 变更 _snapshot 的状态为 ConnectionState.waiting ;

  4. 接着对 Future 调用 then 方法,这里主要就是先判断了 callbackIdentity 是否相等,如果不相等,那么这个 Future肯定是更改了,或者已经 dispose 了。如果 callbackIdentity 相等, 则继续判断是有错误还是有数据 ,有数据就调用 AsyncSnapshot<T>.withData ,有错误就调用 AsyncSnapshot<T>.withError ,并传入状态。

didUpdateWidget

接着下面是 didUpdateWidget 方法,该方法主要是用来判断是否需要更新 widget:

@override
void didUpdateWidget(FutureBuilder<T> oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (oldWidget.future != widget.future) {
    if (_activeCallbackIdentity != null) {
      _unsubscribe();
      _snapshot = _snapshot.inState(ConnectionState.none);
    }
    _subscribe();
  }
}
复制代码

这里更新的逻辑是判断 future 是否一样,如果不一样则:

_activeCallbackIdentity
_activeCallbackIdentity = null;
ConnectionState.none

dispose()

最后就是 dispose() 方法:

@override
void dispose() {
  _unsubscribe();
  super.dispose();
}
复制代码

FutureBuilder 重写该方法来达到 dispose 时自动取消订阅。

总结

Future 的状态无非三种:

  1. 未开始
  2. 进行中
  3. 已完成

其中 已完成 又分为两种:

  1. 有数据
  2. 有异常

其实可以看到,FutureBuilder 大体上的思路就是对 Future 状态的封装,从而达到我们想要的效果。

在 Flutter 中,我们可以通过查看源码来获取很多的灵感,因为 Flutter 的 注释写的简直不要太到位

FutureBuilder源码分析

以上所述就是小编给大家介绍的《FutureBuilder源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

新媒体运营实战技能

新媒体运营实战技能

张向南 勾俊伟 / 人民邮电出版社 / 2017-5 / 39.80元

《新媒体运营实战技能》共7章。第1章重点介绍了新媒体图片的创意思路及制作技巧,包括微信公众号封面图、信息长图、icon图标、九宫图、gif图片的具体实战操作;第2章重点介绍了创意云文字、微信排版、滑动看图等新媒体文字的排版方法与处理技巧;第3章是新媒体表单,引导读者对表单结构、设计场景及具体应用全面了解;第4章关于H5的创意思路及制作方法,解析了引发H5传播的心理因素,并重点介绍H5的制作工具与具......一起来看看 《新媒体运营实战技能》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器