FutureBuilder源码分析

本文详细分析了FutureBuilder的构造函数、AsyncWidgetBuilder、AsyncSnapshot和_FutureBuilderState等关键部分,解释了其内部工作原理,包括初始化、订阅、更新和释放过程。通过源码阅读,揭示了FutureBuilder如何处理异步数据的状态,以及如何根据数据状态构建UI。
摘要由CSDN通过智能技术生成

关于 FutureBuilder 的使用,我在之前的公众号文章中有写过,

如果没看过的可以跳转:Flutter FutureBuilder 异步UI神器.

FutureBuilder

首先看 FutureBuilder<T> 类。

构造函数

 
 
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 是否一样,如果不一样则:

1.判断 _activeCallbackIdentity 是否为 null2.unsubscribe(),取消订阅。这里就一行代码:_activeCallbackIdentity = null;3.把 _snapshot 的状态置为 ConnectionState.none4.subscribe(),重新订阅。

dispose()

最后就是 dispose()方法:

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

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

总结

Future 的状态无非三种:

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

其中 已完成 又分为两种:

1.有数据2.有异常

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

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

640?wx_fmt=jpeg


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值