Flutter-未来的建设者:我什么时候应该使用它

Lit*_*key 12 future builder dart flutter

我想知道何时应该使用将来的构建器。例如,如果我要发出http请求并在列表视图中显示结果,则一旦打开视图,我是否必须使用future构建器或仅构建ListViewBuilder类似的构建器:

new ListView.builder(
        itemCount: _features.length,
        itemBuilder: (BuildContext context, int position) {
...stuff here...
}
Run Code Online (Sandbox Code Playgroud)

而且,如果我不想构建列表视图,而是想要构建一些更复杂的东西(例如圆形图表),是否应该使用Future Builder?

希望它足够清楚!

Din*_*ian 21

FutureBuilder 删除一些样板代码

假设您要fetch data from backend启动页面并显示加载程序,直到数据到来。

ListBuilder的任务:

  • 有两个状态变量1. dataFromBackend2。isLoadingFlag
  • 在启动时,设置isLoadingFlag = true并根据显示loader
  • 数据到达后,请根据您的数据来设置数据backend并进行设置isLoadingFlag = falsesetState显然在内部)
  • 我们需要有一个if-elsewidget创作。如果isLoadingFlagtrue,则显示loader其他显示data。如果失败,请显示error message

FutureBuilder的任务:

  • futureFuture Builder中提供异步任务
  • 基于connectionState,秀messageloadingactive(streams)done
  • 基于data(snapshot.hasError)显示视图

FutureBuilder的优点

  • two flags,不setState
  • 反应式编程(FutureBuilder将负责更新有关数据到达的视图)

例:

    new FutureBuilder<String>(
        future: _fetchNetworkCall, // async work
        builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
           switch (snapshot.connectionState) {
             case ConnectionState.waiting: return new Text('Loading....');
             default:
               if (snapshot.hasError)
                  return new Text('Error: ${snapshot.error}');
               else
              return new Text('Result: ${snapshot.data}');
            }
         },
        )
Run Code Online (Sandbox Code Playgroud)

性能影响:

我只是看了一下FutureBuilder代码,以了解使用它的性能影响。

  • FutureBuilder只是StatefulWidgetstate变量为_snapshot
  • 初始状态为 _snapshot = new AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
  • 订阅future我们要发送的构造函数并state基于该更新。

    widget.future.then<void>((T data) {
        if (_activeCallbackIdentity == callbackIdentity) {
      setState(() {
        _snapshot = new AsyncSnapshot<T>.withData(ConnectionState.done, data);
       });
     }
    }, onError: (Object error) {
    if (_activeCallbackIdentity == callbackIdentity) {
      setState(() {
        _snapshot = new AsyncSnapshot<T>.withError(ConnectionState.done, error);
      });
     }
    });
    
    Run Code Online (Sandbox Code Playgroud)

因此,这FutureBuilder是我们通常所做的工作的包装/样板。因此,不应有任何性能影响。

  • 所以我不需要它,但这个决定将是一个糟糕的决定,因为它对我有很大帮助。谢谢! (2认同)

Mij*_*man 18

FutureBuilder 是一个小部件,它将帮助您执行一些异步函数,并根据该函数\xe2\x80\x99s 结果,您的 UI 将更新。

\n

我列出了一些用例,为什么你会使用 FutureBuilder?

\n
    \n
  1. 如果您想在异步任务之后渲染小部件,请使用它。

    \n
  2. \n
  3. 我们可以通过简单地使用来处理加载过程ConnectionState.waiting

    \n
  4. \n
  5. 不需要任何自定义错误控制器。可以简单地处理错误dataSnapshot.error != null

    \n
  6. \n
  7. 由于我们可以在构建器中处理异步任务,因此我们不需要任何setState(() { _isLoading = false; });

    \n
  8. \n
\n

当我们使用 FutureBuilder 小部件时,我们需要检查未来状态,即未来是否已解决等等。有以下几种状态:

\n
    \n
  1. ConnectionState.none: 这意味着 future 为 null,initialData 用作 defaultValue。

    \n
  2. \n
  3. ConnectionState.active:这意味着未来不为零,但尚未解决。

    \n
  4. \n
  5. ConnectionState.waiting:这意味着未来正在解决,我们很快就会得到结果。

    \n
  6. \n
  7. ConnectionState.done:这意味着未来已经解决了。

    \n
  8. \n
\n

一个简单的实现

\n

这里 OrdersProvider 是一个提供者类,而 fetchAndSetOrders() 是该提供者类的方法。

\n
body: FutureBuilder(\n        future: Provider.of<OrdersProvider>(context, listen: false)\n            .fetchAndSetOrders(),\n        builder: (context, dataSnapshot) {\n          if (dataSnapshot.connectionState == ConnectionState.waiting) {\n            return Center(\n              child: CircularProgressIndicator(),\n            );\n          } else {\n            if (dataSnapshot.error != null) {\n              return Center(\n                child: Text('An error occured'),\n              );\n            } else {\n              return Consumer<OrdersProvider>(\n                builder: (context, orderData, child) => ListView.builder(\n                  itemCount: orderData.orders.length,\n                  itemBuilder: (context, i) => OrderItem(orderData.orders[i]),\n                ),\n              );\n            }\n          }\n        },\n      ),\n
Run Code Online (Sandbox Code Playgroud)\n


San*_*inh 6

FutureBuilder 示例

  • 当您想在异步调用后对小部件进行排序时,请使用 FutureBuilder()

    class _DemoState extends State<Demo> {
    
    @override
    Widget build(BuildContext context) {
      return FutureBuilder<String>(
        future: downloadData(), // function where you call your api
        builder: (BuildContext context, AsyncSnapshot<String> snapshot) {  // AsyncSnapshot<Your object type>
          if( snapshot.connectionState == ConnectionState.waiting){
              return  Center(child: Text('Please wait its loading...'));
          }else{
              if (snapshot.hasError)
                return Center(child: Text('Error: ${snapshot.error}'));
              else
                return Center(child: new Text('${snapshot.data}'));  // snapshot.data  :- get your object which is pass from your downloadData() function
          }
        },
      );
    }
    Future<String> downloadData()async{
      //   var response =  await http.get('https://getProjectList');    
      return Future.value("Data download successfully"); // return your response
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

在future builder中,它调用future函数来等待结果,一旦它产生结果,它就会调用我们构建widget的builder函数。

AsyncSnapshot 有 3 种状态:

  1. connectionState.none = 在这种状态下未来为空

  2. connectionState.waiting = [future] 不为空,但尚未完成

  3. connectionState.done = [future] 不为空,并且已经完成。如果未来成功完成,[AsyncSnapshot.data] 将设置为未来完成的值。如果它以错误完成,则 [AsyncSnapshot.hasError] 将为 true

  • 需要注意的是,每次通过build(...)函数都会执行downloadData()函数。最佳实践是调用 downloadData() 并将返回的 Future 保存到 State 对象中的变量中,并在将来引用该变量:参数 (4认同)