关于 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.none
4.subscribe(),重新订阅。
dispose()
最后就是 dispose()
方法:
@override
void dispose() {
_unsubscribe();
super.dispose();
}
FutureBuilder 重写该方法来达到 dispose
时自动取消订阅。
总结
Future 的状态无非三种:
1.未开始2.进行中3.已完成
其中 已完成 又分为两种:
1.有数据2.有异常
其实可以看到,FutureBuilder 大体上的思路就是对 Future 状态的封装,从而达到我们想要的效果。
在 Flutter 中,我们可以通过查看源码来获取很多的灵感,因为 Flutter 的 注释写的简直不要太到位!