“This is the 25th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

FutureBuilder

In actual development, it is very common to perform network request to load data and display data after entering a page. At this time, we usually display loading until the loading is complete and the normal page is displayed. In flutter we can make an asynchronous request in initState, assign the request result to data and refresh the page with setState. This can be done in build

if(data == null) {return _LoadingWidget()
}
else{
    return. }Copy the code

Flutter actually provides a FutureBuilder to handle components that need to be asynchronous. Here is a simple example:

var _future = Future.delayed(Duration(seconds: 3), () {
    return 'Data returned by server';
  });
 
FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        var widget;
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {
            widget = Text("Something went wrong.");
          } else{ widget = Text(snapshot.data); }}else {
          widget = Padding(
            padding: EdgeInsets.all(20),
            child: CircularProgressIndicator(),
          );
        }
 
        returnCenter( child: widget, ); });Copy the code

You can see that FutureBuilder has two main properties

  • Future: Tasks to be processed asynchronously. Such as requesting data, reading files and so on
  • Builder: Create the widget. Its snapshot is the current state of the component, through which we can realize the component switch.

ConnectionState of snapshot indicates the status of the asynchronous task. If connectionState. Done indicates that the task is complete. Otherwise, the task is in progress. We use these states to return different components for asynchronous loading.

When the task is complete (connectionstate. done with snapshot.hasError set to false), we can use snapshot.data to fetch asynchronously returned data and then render the page.

Prevent FutureBuilder from repainting

FutureBuilder is a StatefulWidget. If the parent rebuilds the widget, FutureBuilder will also rebuild the widget, but we may not be asking for data at all. We may just be updating a copy on the page, which will cause unnecessary waste and consumption. We want to avoid it, so we need to prevent FutureBuilder from redrawing.

FutureBuilder redraw source code as follows:

@override
  void didUpdateWidget(FutureBuilder<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if(oldWidget.future ! = widget.future) {if(_activeCallbackIdentity ! =null) { _unsubscribe(); _snapshot = _snapshot.inState(ConnectionState.none); } _subscribe(); }}Copy the code

As you can see, it is used to determine if fuTrue is the same object to perform the redraw, so we simply assign the asynchronous task function to a variable in advance, and then use the variable in FutureBuilder as follows:

var _mFuture;
 
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _mFuture = _future();
  }
 
 _future() async{... } FutureBuilder( future: _mFuture, ... )Copy the code

Someone asked if assigning a function directly would achieve the same effect, for example:

 _future() async{... } FutureBuilder( future: _future(), ... )Copy the code

According to the summary of netizens, it is not possible. For verification.