flutterstatepull-to-refreshflutter-futurebuilder

How to use RefreshIndicator to update FutureBuilder state?


I am using FutureBuilder to show the data loaded from server. I want to show the loading state only once when the app starts, that is why I am calling the API from initState. The data I get from server may change and to reflect the change in UI, I am using refreshIndicator. The problem is that I could not come up with a solution to update the state.

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
      GlobalKey<RefreshIndicatorState>();
  Future<List<Photo>> _photosServer;

  @override
  void initState() {
    super.initState();
    _photosServer = ApiRest.getPhotos();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: RefreshIndicator(
        key: _refreshIndicatorKey,
        onRefresh: () {
          _refreshIndicatorKey.currentState.show();
          await getPhotosFromServer();
          ...
        },
        child: FutureBuilder(
          future: _photosServer,
          builder: (BuildContext context, snapshot) {
            if (snapshot.data == null) {
              return Center(
                child: Text('Loading...'),
              );
            }
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, index) => ListTile(
                title: Text(snapshot.data[index].title),
              ),
            );
          },
        ),
      ),
    );
  }
}

In the onRefresh function, I am using the following code to show the RefreshIndicator while getting data from server.

onRefresh: () {
          _refreshIndicatorKey.currentState.show();
          await getPhotosFromServer();

           ...

        }

What else should I do to handle the issue?


Solution

  • You can have a separate List<Photo> variable which can be updated by the FutureBuilder or the RefreshIndicator, and do something like this:

    class _MyHomePageState extends State<MyHomePage> {
      GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
          GlobalKey<RefreshIndicatorState>();
      List<Photo> _photosList;
      Future<void> _initPhotosData;
    
      @override
      void initState() {
        super.initState();
        _initPhotosData = _initPhotos();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: FutureBuilder(
            future: _initPhotosData,
            builder: (BuildContext context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                case ConnectionState.waiting:
                case ConnectionState.active:
                  {
                    return Center(
                      child: Text('Loading...'),
                    );
                  }
                case ConnectionState.done:
                  {
                    return RefreshIndicator(
                        key: _refreshIndicatorKey,
                        onRefresh: _refreshPhotos,
                        child: ListView.builder(
                          itemCount: _photosList.length,
                          itemBuilder: (BuildContext context, index) => ListTile(
                            title: Text(_photosList[index].title),
                          ),
                        ));
                  }
              }
            },
          ),
        );
      }
    
      Future<void> _initPhotos() async {
        final photos = await ApiRest.getPhotos();
        _photosList = photos;
      }
    
      Future<void> _refreshPhotos() async {
        final photos = await ApiRest.getPhotos();
        setState(() {
          _photosList = photos;
        });
      }
    }