FutureBuilder刷新數據的方式

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;
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章