IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter: FutureBuilder 组件的使用 -> 正文阅读

[移动开发]Flutter: FutureBuilder 组件的使用

如果需要 render 的数据需要使用 http 请求从后端获取,那么从发送请求到最终获得数据之间必然会有延时,使用一般的方法,就需要加上额外的变量如 _isLoading 判断数据是否在加载,如果是,则加载 spinner 组件等等,代码相对繁琐:

以下是一个显示若干条订单 (orders) 的页面,orders_screen.dart:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/app_drawer.dart';
import '../providers/orders.dart' show Orders;
import '../widgets/order_item.dart';

class OrdersScreen extends StatefulWidget {
  static const routeName = '/orders';

  
  State<OrdersScreen> createState() => _OrdersScreenState();
}

class _OrdersScreenState extends State<OrdersScreen> {
  var _isLoading = false;

  
  void initState() {
    Future.delayed(Duration.zero).then((_) async {
      setState(() {
        _isLoading = true;
      });
      await Provider.of<Orders>(context, listen: false).fetchAndSetOrders();
      setState(() {
        _isLoading = false;
      });
    });
    super.initState();
  }

  
  Widget build(BuildContext context) {
    final orderData = Provider.of<Orders>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Orders Screen'),
      ),
      drawer: AppDrawer(),
      body: _isLoading
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: orderData.orders.length,
              itemBuilder: (ctx, i) => OrderItem(orderData.orders[i]),
            ),
    );
  }
}

改为使用 FutureBuilder,代码比较起来更为优雅:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/app_drawer.dart';
import '../providers/orders.dart' show Orders;
import '../widgets/order_item.dart';

class OrdersScreen extends StatefulWidget {
  static const routeName = '/orders';

  
  State<OrdersScreen> createState() => _OrdersScreenState();
}

class _OrdersScreenState extends State<OrdersScreen> {
  Future _ordersFuture;

  Future _obtainOrdersFuture() {
    return Provider.of<Orders>(context, listen: false).fetchAndSetOrders();
  }

  
  void initState() {
    _ordersFuture = _obtainOrdersFuture();
    super.initState();
  }

  
  Widget build(BuildContext context) {
    print('building orders');
    // final orderData = Provider.of<Orders>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Orders Screen'),
      ),
      drawer: AppDrawer(),
      body: FutureBuilder(
        future: _ordersFuture,
        builder: (ctx, dataSnapshot) {
          if (dataSnapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else {
            if (dataSnapshot.error != null) {
              return Center(child: Text('An error occurred.'));
            } else {
              return Consumer<Orders>(
                builder: (ctx, orderData, child) => ListView.builder(
                  itemCount: orderData.orders.length,
                  itemBuilder: (ctx, i) => OrderItem(orderData.orders[i]),
                ),
              );
            }
          }
        },
      ),
    );
  }
}


StackOverflow 上的 FutureBuilder
https://stackoverflow.com/questions/51983011/when-should-i-use-a-futurebuilder

FutureBuilder removes boilerplate code.

Let’s say you want to fetch some data from the backend on page launch and show a loader until data comes.


FutureBuilder 删除了样板代码。

假设在页面启动时需要从后端获取一些数据,在此期间显示 loader,直到数据到来。


Tasks for ListBuilder:

ListBuilder 的任务:

  • Have two state variables, dataFromBackend and isLoadingFlag
  • On launch, set isLoadingFlag = true, and based on this, show loader.
  • Once data arrives, set data with what you get from backend and set isLoadingFlag = false (inside setState obviously)
  • We need to have a if-else in widget creation. If isLoadingFlag is true, show the loader else show the data. On failure, show error message.

  • 有两个状态变量,dataFromBackendisLoadingFlag
  • 在启动时,设置 isLoadingFlag = true,并在此基础上显示 loader。
  • 数据到达后,使用从后端获得的数据设置数据并设置 isLoadingFlag = false (显然在 setState 内部)
  • 我们需要在创建小部件时使用 if-else。如果 isLoadingFlagtrue,则显示 loader,否则显示数据。失败时,显示错误消息。

Tasks for FutureBuilder:

FutureBuilder 的任务:

  • Give the async task in future of Future Builder
  • Based on connectionState, show message (loading, active(streams), done)
  • Based on data(snapshot.hasError), show view

  • 给 Future Builder 未来的异步任务 ??
  • 基于connectionState,显示消息 (loading, active(streams), done)
  • 基于数据(snapshot.hasError),显示视图

Pros of FutureBuilder

FutureBuilder 的优点

  • Does not use the two state variables and setState
  • Reactive programming (FutureBuilder will take care of updating the view on data arrival)
    Example:

  • 不使用两个状态变量和 setState
  • 反应式编程(FutureBuilder 将负责在数据到达时更新视图)
    例子:
FutureBuilder<String>(
    future: _fetchNetworkCall, // async work
    builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
       switch (snapshot.connectionState) {
         case ConnectionState.waiting: return Text('Loading....');
         default:
           if (snapshot.hasError)
              return Text('Error: ${snapshot.error}');
           else
          return Text('Result: ${snapshot.data}');
        }
      },
    )

Performance impact:

性能影响:

I just looked into the FutureBuilder code to understand the performance impact of using this.

FutureBuilder is just a StatefulWidget whose state variable is _snapshot
Initial state is _snapshot = AsyncSnapshot.withData(ConnectionState.none, widget.initialData);
It is subscribing to future which we send via the constructor and update the state based on that.
Example:

我只是查看了 FutureBuilder 代码以了解使用它对性能的影响。
FutureBuilder 只是一个 StatefulWidget,它的 state 变量是 _snapshot
初始状态为 _snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
它订阅了 future, 我们通过构造函数发送 future, 并基于它更新 state
例子:

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);
    });
  }
});

So the FutureBuilder is a wrapper/boilerplate of what we do typically, hence there should not be any performance impact.

所以 FutureBuilder 是我们通常做的一个包装器/样板,因此不应该有任何性能影响。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:23:00  更:2022-09-04 01:23:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:39:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码