FutureBuilder刷新數據的方式
源碼
///訂閱
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);
}
}
///取消訂閱
void _unsubscribe() {
_activeCallbackIdentity = null;
}
我們發現,想要刷新FutureBuilder的數據,核心方法就是觸發他的_subscribe()
方法。然後看一下這個方法是在哪裏調用的:
@override
void initState() {
super.initState();
_snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
_subscribe();
}
@override
void didUpdateWidget(FutureBuilder<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.future != widget.future) {
if (_activeCallbackIdentity != null) {
_unsubscribe();
_snapshot = _snapshot.inState(ConnectionState.none);
}
_subscribe();
}
}
由源碼所見,只有當FutureBuilder創建的時候,和他所在父組件setState
的時候纔會觸發數據刷新。
解決方案
我們可以用StateFulWidget
包裹FutureBuilder,想要刷新FutureBuilder的數據,只需要刷新這個StateFulWidget就可以了,這樣就不會影響到widgetTree中的其他組件。
import 'package:flutter/material.dart';
class RefreshableFutureBuilder<T> extends StatefulWidget {
RefreshableFutureBuilder(
{Key key,
this.future,
this.initialData,
this.builder})
: super(key: key);
final Future<T> Function() future;
final T initialData;
final AsyncWidgetBuilder<T> builder;
@override
State<StatefulWidget> createState() => _RefreshableFutureBuilderState<T>();
}
class _RefreshableFutureBuilderState<T>
extends State<RefreshableFutureBuilder> {
@override
Widget build(BuildContext context) => FutureBuilder(
future: widget.future(),
initialData: widget.initialData,
builder: widget.builder);
}
調用
GlobalKey _key = GlobalKey();
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
child: Text('點我'),
onPressed: () {
_key.currentState.setState(() {
});
},
),
body: Center(
child: RefreshableFutureBuilder<List<ResponseData>>(
key: _key,
future: _getData,///注意這裏傳入的是方法,而不是方法返回值!!!
initialData: [],
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
Scaffold.of(context)
.showSnackBar(SnackBar(content: snapshot.error));
return Container();
}
switch (snapshot.connectionState) {
case ConnectionState.none:
return Container();
case ConnectionState.active:
return Container();
case ConnectionState.waiting:
return CircularProgressIndicator();
default: // case ConnectionState.done:
return ListView.separated(
itemCount: snapshot.data.length,
separatorBuilder: (_, index) => Divider(),
itemBuilder: (_, index) => ListTile(
title: Text(snapshot.data[index].name),
),
);
}
}),
),
);
///訪問接口方法
Future<List<ResponseData>> _getData() async {
var jsonData =
await Dio().get('https://wanandroid.com/wxarticle/chapters/json');
var result = ResponseEntity().fromJson(jsonData.data).data;
return result;
}