【问题标题】:future.then block skipped inside function of return type integer causes to return nullfuture.then 块在返回类型整数的函数内跳过导致返回 null
【发布时间】:2020-04-02 19:31:21
【问题描述】:

我偶然发现了一个奇怪的问题。

以下函数获取 Firestore 文档并将其返回,以便其他函数可以访问它的数据

Future getCountRequests() async {
  try{
    return await _countReference.document('Requests').get();
  } catch(e){
    print(e.toString());
  }
}

这就是使用它的数据的函数。

int _countRequest() {
  int toReturn;

  CounterService().getCountRequests().then(
    (doc) {
      //print('Item in question: $doc, information from document ${doc.data}'); 
      //this line prints correctly Instance of DocumentReference and {"amount" : 6}
      toReturn = doc.data['amount'];
    }
  );
  return toReturn;
}

当我运行代码时,我在屏幕上收到一条错误消息,指出我正在使用的 AnimatedList_countRequest() 函数接收到 null。

在这一行打断有助于我理解这个块被完全跳过

CounterService().getCountRequests().then( ...

但是,当我在这一行上打断时,它表明块内的代码有效,并且确实通过getCountRequests() 函数接收到该文档。

toReturn = doc.data['amount'];

我的问题是,是什么导致 .then 块被跳过导致函数返回 null?

【问题讨论】:

  • 您应该在要获取的未来函数之前添加await
  • 请参阅这些指南 [1] 以了解“等待”的一些示例。 [1]dart.dev/codelabs/…
  • 是的,我访问了这些页面。根据我从其他几篇文章的理解,“then”函数应该可以从异步函数中获取值并使其在同步函数中可用。这就是我在这里尝试的,所以这让我想知道我做错了什么。
  • then() 方法在您从_countRequest 方法返回后被调用,这就是您得到null 的原因,因为toReturn 没有设置为它的任何值声明
  • 感谢您的回复,我明天会尝试您的解决方案,如果它有效,请告诉您。

标签: asynchronous flutter dart google-cloud-firestore future


【解决方案1】:

你试图做的事情行不通。

您正在尝试从同步函数返回异步计算的结果。没有办法让它发挥作用。 异步计算总是稍后完成,同步函数总是返回now,所以现在不能返回计算结果。

then 调用是使操作异步的原因。它将回调传递给未来,但唯一可以保证当回调被调用时,它肯定是不是立即的。 then 调用立即返回,返回一个将在回调被调用时完成的未来,并且您的代码返回toReturn 的当前值,它仍然是null

【讨论】:

    【解决方案2】:

    最后,我发现用FutureBuilder 异步执行此操作根本行不通,或者以我目前的技能组合,我只是不知道如何使它工作。所以我决定转换为StreamBuilder,它使用从以下函数获得的Stream<QuerySnapshot>

    Stream<QuerySnapshot> findAllRequests() {
      try{
        return accountRequestCollection.snapshots();
      } catch(e){
        print(e.toString());
        return null;
      }
    }
    

    并像这样将AnimatedList 构建到StreamBuilder 中。

    class Request extends StatefulWidget {
      @override
      _RequestState createState() => _RequestState();
    }
    
    class _RequestState extends State<Request> {
    
      final AdministrationService _administrationService = AdministrationService();
      final GlobalKey<AnimatedListState> _globalKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Account Requests'),
          ),
          body: StreamBuilder(
            stream: _administrationService.findAllRequests(),
            builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.waiting: return new Loading();
                default: if (snapshot.hasError) {
                  return new Text('Error: ${snapshot.hasError}');
                } else {
                  return AnimatedList(
                    key: _globalKey,
                    initialItemCount: snapshot.data.documents.length,
                    itemBuilder: (BuildContext context, int index, Animation animation) {
                      return _buildItem(snapshot.data.documents[index].data['email'], animation);
                    }
                  );    
                }
              }
            }
          )
        );
      }
    
      Widget _buildItem(String item, Animation animation) {
        return SizeTransition(
          sizeFactor: animation,
          child: Card(
            child: ListTile(
              title: Text(
                item,
                style: TextStyle(
                  fontSize: 20.0,
                )
              ),
            ),
          ),
        );
      }
    }
    

    它会进入这个页面。 Emulator Screenshot。 我希望这个解决方案可以帮助其他有类似问题的人,但考虑到这只是一个概念验证产品,我不确定这在 Firestore 读/写方面会付出多大的代价。

    【讨论】:

      猜你喜欢
      • 2015-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      • 2020-01-20
      • 2013-09-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多