future.then 块在返回类型整数的函数内跳过导致返回 null

Posted

技术标签:

【中文标题】future.then 块在返回类型整数的函数内跳过导致返回 null【英文标题】:future.then block skipped inside function of return type integer causes to return 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 没有设置为它的任何值声明 感谢您的回复,我明天会尝试您的解决方案,如果它有效,请告诉您。 【参考方案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 读/写方面会付出多大的代价。

【讨论】:

以上是关于future.then 块在返回类型整数的函数内跳过导致返回 null的主要内容,如果未能解决你的问题,请参考以下文章

future then

FlutterFuture 异步编程 ( 简介 | then 方法 | 异常捕获 | asyncawait 关键字 | whenComplete 方法 | timeout 方法 )

java基础:java中的方法

“查询结构与函数结果类型不匹配。返回类型双精度与第 1 列中的预期类型整数不匹配。”?

PL/SQL 函数返回类型整数:无效标识符

Fat Arrow是语法糖 - 但不会返回