我如何在 FutureBuilder Widget 的构建器函数中等待 - Flutter

Posted

技术标签:

【中文标题】我如何在 FutureBuilder Widget 的构建器函数中等待 - Flutter【英文标题】:How can I await inside the builder function of FutureBuilder Widget - Flutter 【发布时间】:2021-06-27 04:45:26 【问题描述】:

我试图在 FutureBuilder 内两次从 firebase 检索数据,第一次是“future:”参数负责检索数据。但是,当我第二次尝试从 firebase 检索“restaurant”数据时,我收到一个 null 错误,因为我不能等待“getRestauran()”函数完成执行。如果我在函数之前添加“等待”,则会出现错误,因为“异步”无法应用于“构建器”函数。

有没有办法让它工作?

Future<Restaurant> getRestaurant(String restaurantId) async 
    Map<String, dynamic> restaurantData;
    String id;
    await FirebaseFirestore.instance
        .collection('restaurants')
        .doc(restaurantId)
        .get()
        .then((value) 
      restaurantData = value.data();
      id = value.id;
    );
    print(restaurantData);
    final restaurant1 = Restaurant(
      id: id,
      name: restaurantData['name'],
      description: restaurantData['description'],
      // cuisine: List<String>.from(restaurant['cuisine']),
      imageUrl: restaurantData['imageUrl'],
      isAvailable: restaurantData['isAvailable'],
      isFavourite: restaurantData['isFavourite'],
      pickupTime: restaurantData['pickupTime'].toDate(),
      stars: restaurantData['stars'].toDouble(),
      location: Location(
        address: restaurantData['location']['address'],
        city: restaurantData['location']['city'],
        latitude: restaurantData['location']['latitude'],
        longitude: restaurantData['location']['longitude'],
        zipcode: restaurantData['location']['zipcode'],
        locality: restaurantData['location']['locality'],
      ),
      // items: restItems,
      // reviews: reviews,
    );
    return restaurant1;
  

  @override
  Widget build(BuildContext context) 
    final cart = Provider.of<Cart>(context);
    final order = Provider.of<Order>(context);
    // cartItems =
    //     Provider.of<Cart>(context, listen: false).cartItems.values.toList();
    //print(cartItems[0].title);
    final Size size = MediaQuery.of(context).size;
    return Scaffold(
      body:
          // cartItems.isEmpty
          //     ? Center(
          //         child: Text(
          //           'Your Cart is Empty',
          //           style: TextStyle(
          //             color: kTextLightColor,
          //             fontSize: 18,
          //           ),
          //         ),
          //       )
          // :
          FutureBuilder<List<CartItem>>(
              future: cart.fetchCartItems(),
              builder: (context, snapshot) 
                if (!snapshot.hasData) 
                  //Navigator.of(context).pushNamed('loading');
                  return Center(child: CircularProgressIndicator());
                

                List<CartItem> cartItems = snapshot.data;
                print(cartItems[0].restaurantId);
                Map<String, dynamic> restaurantData;
                String id;
                
                restaurant = getRestaurant(cartItems[0].restaurantId);
                
                print('$restaurant: Restaurant Data');
                // return isComplete
                return CartWidget(
                    restaurant: restaurant,
                    cart: cart,
                    cartItems: cartItems,
                    order: order);
                // : CircularProgressIndicator();
              ),
    );
  
  

【问题讨论】:

【参考方案1】:

一般来说,您不能在构建方法中使用await。您可以调用函数,但不能等待它们。 Future builder 解决了这个问题。

在你的情况下,你需要两个未来的建设者,而你已经找到了第一个。

The solution is to go to your `CartWidget`, when you define it, add a required string to it like this, instead of requiring a `restaurant` object, you require a `restaurantId`:

class CartWidget extends StatelessWidget
final String restaurantId;
const CartWidget(required this.restaurantId);
//.
//.
// the rest of your widget logic, also move this function completely to this widget
//Future<Restaurant> getRestaurant(String restaurantId) async 

然后,在您的构建中,当涉及到餐厅时,请使用未来的构建器,并使用您移至此处的功能来获取它。它会解决你的问题。

【讨论】:

链接FutureBuilders 不是一个好的解决方案-相反,您应该将Futures 链接在一个async 方法中-如果您有一个包含3 个或更多嵌套@987654326 的链怎么办@s?你会使用 3 个或更多嵌套的 FutureBuilders 吗? 你能指出链接 F.Builders 的问题吗?将它们链接在一起有什么问题,但是可以链接异步函数来构建它们?它实际上可以更好地控制屏幕上显示的内容,并且不会过度获取数据,尤其是在每个请求都很重要的情况下,当涉及到 firebase 时。这就是 F.Builders 的用途,您不必等待所有功能完成。无论完成什么,都会显示在屏幕上。请提供你的论点,我对你的观点很感兴趣,如果你能证明我的观点,我准备改变我的观点 我是 Flutter 新手,所以我对这个 lol 了解不多。我在考虑保存请求,你说的也有道理,这就是我打算包括餐厅信息的原因。在我的购物车收藏中。但是,如果您能为我提供一个更好的解决方案来节省 firebase 中的读写次数,我将不胜感激。谢谢:) ok 以sqflite 包为例,假设它应该显示基于上一个会话的数据(例如,您的应用显示一些电子书,并且在上一个会话中您存储在shared_preferences电子书路径(电子书作为 sqlite db 分发,用于快速文本搜索)和您停止阅读的页码) [继续...] 所以你必须首先阅读那些为你提供书籍路径和页码的共享偏好 - 这是Future“one”,然后基于你必须打开那个 sqlite 数据库 - 这是Future“二”,最后当你拥有那个数据库时,你从最后一个阅读页面读取内容 - 这是一个 Future “三” - 现在你真的会创建 3 FutureBuilders 吗?或者你只做await shared_prefs,然后是await open_db,然后是await readContent——所有这些都在一个async方法中

以上是关于我如何在 FutureBuilder Widget 的构建器函数中等待 - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

FlutterFuture 与 FutureBuilder 异步编程代码示例 ( FutureBuilder 构造函数设置 | 处理 Flutter 中文乱码 | 完整代码示例 )

如何在 FutureBuilder() 中正确“刷新”小部件

如何在 FutureBuilder Flutter 中停止循环 SetState

如何在 FutureBuilder 中解析从本地主机接收的 JSON 对象

如何将快照数据从 futurebuilder 传递到同一页面中的另一个 futurebuilder?

在 FutureBuilder 的情况下,我应该如何获得一组可滚动的小部件而不会溢出