【问题标题】:Trying to implement loading spinner while loading data from Firestore with Flutter尝试在使用 Flutter 从 Firestore 加载数据时实现加载微调器
【发布时间】:2020-01-08 22:33:33
【问题描述】:

我正在开发一个应用程序,该应用程序在后端从 Firestore 加载数据时显示微调器,但它没有按预期工作,我很难找到缺陷。

我的订单页面代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:table_service/providers/order.dart';

import '../providers/session.dart';

class OrdersPage extends StatefulWidget {
  bool isLoading = true;

  @override
  _OrdersPageState createState() => _OrdersPageState();
}

class _OrdersPageState extends State<OrdersPage> {
  List<Order> _orders = [];
  @override
  Widget build(BuildContext context) {
    final session = Provider.of<Session>(context, listen: false);

    return Scaffold(
      floatingActionButton: session.privilege == 'Administrator' ||
              session.privilege == 'Waiter' ||
              session.privilege == 'Customer'
          ? FloatingActionButton(
              heroTag: 'OrdersPageFAB',
              onPressed: () {},
              child: Icon(Icons.add, color: Colors.white),
            )
          : null,
      body: FutureBuilder(
        future: session.fetchOrdersData(),
        builder: (ctx, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else {
            print(snapshot.data);
            return GridView.builder(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                childAspectRatio: 2 / 2,
              ),
              itemCount: _orders.length,
              itemBuilder: (_, i) {
                return Padding(
                  padding: const EdgeInsets.all(5.0),
                  child: Card(
                    child: GridTile(
                      child: Icon(
                        Icons.library_books,
                        size: 100.0,
                        color: Colors.grey,
                      ),
                      footer: GridTileBar(
                        backgroundColor: Colors.black54,
                        title: Text('Order by: ${_orders[i].name}'),
                      ),
                    ),
                  ),
                );
              },
            );
          }
        },
      ),
    );
  }
}

fetchOrdersData() 处理程序

final Auth auth = Auth();
final Firestore database = Firestore.instance;

String user_name;
String privilege;

List<Food> _foods = [];
List<Order> _orders = [];
List<TransactionModel.Transaction> _transactions = [];

... 
...

Future fetchOrdersData() async  {
  _orders.clear();
  return await  database.collection('orders').getDocuments().then((documents) {
    documents.documents.forEach((order) {
      database
          .collection('users')
          .document(order.data['uid'])
          .get()
          .then((user) {
        _orders.add(Order(
          id: order.documentID,
          tableNumber: order.data['tablenumber'],
          orderDate: (order.data['orderdate'] as Timestamp).toDate(),
          status: order.data['status'],
          note: order.data['note'],
          uid: order.data['uid'],
          name: user.data['user_name'],
        ));
      });
    });
    return _orders;
  });
  notifyListeners();
}

get getOrders {
  return [..._orders];
}

我尝试了很多方法,包括 StreamBuilder、setState() 和最近的 FutureBuilder。 我只是错过了一个重要的代码吗? 还是我用错了方法?

问题是订单页面显示 0 数据,即使 _fetchOrdersData() 上的列表有 1 个元素。

获取完整源代码 here on github

【问题讨论】:

    标签: firebase flutter google-cloud-firestore


    【解决方案1】:

    其他答案看起来很合理。他们只是缺少数据验证检查,我发现我的所有应用程序都需要这些检查。因为如果我有一个良好的连接,并且 hasData 为 true 而 hasError 为 false,那么可能根本没有文档。这应该被检查。这是我项目中的一个 sn-p。

    检查连接状态与检查 snapshot.hasError 相同。

    Widget _getMyFriends() {
    return StreamBuilder<QuerySnapshot>(
      stream: Database.getFriendsByUserId(widget.loggedInUserId),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (snapshot.hasError)
          return Center(child: Text("Error"));
        else if (!snapshot.hasData)
          return Center(child: Text("Loading..."));
        else if (snapshot.data.documents.isEmpty) //also check if empty! show loader?
          return Center(child: Text("No friends added yet."));
        else
          return ListView(
            children: snapshot.data.documents.map((DocumentSnapshot document) {
              return SimpleUserPanel(userId: document['friendid']);
            }).toList(),
          );
      }
    );
    

    }

    【讨论】:

    • 我的订单页面显示0数据,我认为这是从firebase获取数据时有缺陷的异步代码引起的。
    • 您的 fetchOrdersData 代码需要重新编写。您将 async await 与链 .then 承诺混合在一起,然后将它们添加到列表中等。这可能是 99% 的问题所在。您应该希望按原样显示集合中的数据,这是您可以使用 streambuilder 的地方。或者,您可以在初始化时使用适当的异步等待功能(或单击按钮等)下载数据,然后执行您的逻辑,然后显示数据。
    • 您将如何使用 BLoC 模式处理这个问题?我不在 UI 中听流,而是在 Bloc 和使用状态中听。
    • 抱歉不知道,我从来没有在 Flutter 中使用过那种风格,它看起来像是回到了旧的 MVC/MVVM 风格和其他单体风格,这就是响应式、微服务、基于组件的风格颤振/反应被替换。
    【解决方案2】:

    您应该执行以下操作:

    else {
             if(snapshot.hasData){
                print(snapshot.data);
                return GridView.builder(
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    childAspectRatio: 2 / 2,
                  ),
                  itemCount: _orders.length,
                  itemBuilder: (_, i) {
                    return Padding(
                      padding: const EdgeInsets.all(5.0),
                      child: Card(
                        child: GridTile(
                          child: Icon(
                            Icons.library_books,
                            size: 100.0,
                            color: Colors.grey,
                          ),
                          footer: GridTileBar(
                            backgroundColor: Colors.black54,
                            title: Text('Order by: ${_orders[i].name}'),
                          ),
                        ),
                      ),
                    );
                  },
            // By default, show a loading spinner.
             return CircularProgressIndicator();
               },
    

    所以首先使用属性hasData检查snapshot是否有数据,因为这是异步的,它会首先执行return CircularProgressIndicator();然后执行if块。

    【讨论】:

      【解决方案3】:

      查看您的代码,您还必须使用您的snapshot.connectionState == ConnectionState.waiting 检查ConnectionState.active

      实际上,使用FutureBuilderStreamBuilder 时,您拥有更多的权力和控制力。下面是示例代码sn-p:

      switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Center(child: Text("Check Connection"));
          case ConnectionState.active:
          case ConnectionState.waiting:
            return Center(child: CircularProgressIndicator(backgroundColor: Theme.of(context).primaryColorLight,));
          case ConnectionState.done:
            if (snapshot.hasError) {
              return Center(child: Text("Error occured!"));
            } else if (snapshot.hasData) {
              return YourWidgetWithData();
            } else {
              debugPrint("What went wrong");
              return SizedBox();
            }
            break;
          default:
            return SizedBox();
        }
      

      【讨论】:

        猜你喜欢
        • 2020-01-23
        • 2019-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-16
        • 2013-07-24
        • 2019-04-27
        相关资源
        最近更新 更多