【问题标题】:Flutter - Is it possible to extract data from a Future without using a FutureBuilder?Flutter - 是否可以在不使用 FutureBuilder 的情况下从 Future 中提取数据?
【发布时间】:2018-10-22 02:11:59
【问题描述】:

我正在读取来自TextField 的用户提供的输入(在本例中为邮政编码),我需要检查数据库的有效性。但是,我需要在提交按钮(在这种情况下为RaisedButtononPressed: () {} lambda 函数内进行异步数据库查询。在大多数编程语言中,这是一项相当简单明了的任务。然而,我在 Flutter 中遇到的问题是,从异步数据库查询返回的 Future 对象只能由 FutureBuilder 对象使用,而 FutureBuilder 对象又只能返回 Widget 对象。我只需要返回一个String,然后我可以使用它通过MaterialPageRoute 对象传递到新路由,或者在不更改路由的情况下向用户显示错误。有没有办法用 Flutter 做到这一点?返回一个小部件对我来说毫无用处,因为我不想创建一个新的小部件来显示。我正在使用 Flutter 0.3.2 和 Dart 2.0.0

作为我需要调用数据库查询的简化示例:

@override
Widget build(Buildcontext context) {
    return new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
            new Container(
                padding: const EdgeInsets.all(16.0),
                child: new TextField(
                    keyboardType: TextInputType.number,
                    controller: _controller,
                    decoration: new InputDecoration(
                    hintText: 'Zip Code',
                ),
                onSubmitted: (string) {
                  return string;
                },
              ),
            ),
            new RaisedButton(
                onPressed: () {
                        // use regex to test against user input
                        if (_controller.text != null && _controller.text.isNotEmpty) {
                            RegExp zipCodeRegExp = new RegExp(r"^(\d{5})$");

                            // if the user input validates...
                            if (zipCodeRegExp.hasMatch(_controller.text)) {
                            zipCode = _controller.text;

                           // need to perform database query here and return a string, not a Widget

                            } else {
                               // an else condition here
                            }
                        } else {
                           // an else condition here
                        }
                    }
                }
            ),
        ],
    );
}

也许我没有遵循 Flutter 的“口头禅”?感谢您对此的考虑和意见。

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    您可以创建两种方法,一种是提取放入变量中的数据,另一种是像 getter 一样(在我的情况下,我需要使用插件 flutter_secure_storage 访问安全值,而不使用 Futurebuilder )

    mixin SecureStorageMethods {
     String keyValue;
     Future<String> _getFromSecureStorage(String key) async {
     keyValue = await slL<FlutterSecureStorage>().read(key: key);
     return keyValue;
    }
    
    String getSecureValue(String key) {
     _getFromSecureStorage(key);
     return keyValue;
    }
    }
    

    【讨论】:

      【解决方案2】:

      FutureBuilder 只是一个方便的助手,可以在 Future 完成时重建小部件树。

      你可以使用

      funcThatReturnsFuture().then((result) {
        print(result);
        setState(() {
          someVal = result;
        })
      })
      

      Future funcThatMakesAsyncCall() async {
        var result = await funcThatReturnsFuture();
        print(result);  
        setState(() {
          someVal = result;
        })
      }
      

      主要限制是您不能在没有Future 的情况下将值直接返回给调用者,因为无法从异步执行返回到同步执行。

      【讨论】:

      • 是的,我可以理解,但如果我只是创建一个 FutureBuilder 对象实例,它本身会返回一个小部件。那么如何在不将 Widget 本身返回为父 Widget 的一部分的情况下从中获取快照数据呢?
      • 如果你不想构建一个小部件,我不明白你为什么想要一个构建器(任何类型的)
      • 我是否需要同步查询而不是异步查询才能获得 Future 以外的返回类型?这会是我不想要小部件的解决方案吗?
      • 您无法通过网络同步访问服务器,如果可以,这将阻止 UI 直到响应到达。
      • 好的,谢谢你的帮助,Gunter。我很感激:)
      【解决方案3】:

      我后来明白了这一点(我相信这是 Günter 最初所说的,但当时我并不清楚根本原因)。在不创建Widget 对象的情况下使用Future 的唯一方法是使用Future API。 Future API 允许解析 Future 对象,就好像它是 AsyncSnapshot 对象(这是在 FutureBuilder builder: 函数中解析 .data 的地方)。这可以在返回的Future 对象上执行(可以将asyncawait 一起使用)。例如:

      Future regionName = dbClient.getRegionNameFromZipCode(int.parse(zipCode)); <-- this database method getRegionNameFromZipCode returns a Future object and uses async and await
      
      regionName.then((data) {
         String hZonesString = data[0]['hzone'];
         print(hZonesString);
      }, onError: (e) {
           print(e);
         });
      

      一旦您了解了如何利用Future API 以及它的意图与使用FutureBuilder,这将相当简单。很高兴知道这种语言的新手,比如我自己!

      【讨论】:

        【解决方案4】:

        Future 只是回调的语义糖。想象一下你有:

        void fetchName(void Function(String) callback);
        
        void main() {
          fetchName((name) {
             print('Your name is: $name');
          });
        }
        

        没有办法将namefetchName转换(或提取)。它在回调完成之前不存在,并且回调可能不会立即完成(可以从数据库中读取,例如您的示例或网络等)。

        使用FutureBuilder 的优点之一是它确实有助于理解异步抽象,如Future(以及StreamBuilder 用于Stream),并让您专注于编写(同步)构建器代码:

        new FutureBuilder<String>(
          future: _calculation, // a Future<String> or null
          builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none: return new Text('Press button to start');
              case ConnectionState.waiting: return new Text('Awaiting result...');
              default:
                if (snapshot.hasError)
                  return new Text('Error: ${snapshot.error}');
                else
                  return new Text('Result: ${snapshot.data}');
            }
          },
        )
        

        【讨论】:

        • FutureBuilder 声明中的代码似乎只有在返回到父 Widget 时才会执行。例如,当我实例化一个没有返回的 FutureBuilder 时(如return new FutureBuilder),它实际上并没有执行该代码。在构建器中带有 print() 语句的测试:() 方法永远不会执行。就好像您必须使用 Widget 对象。我错过了什么(我很有可能)?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-24
        • 1970-01-01
        相关资源
        最近更新 更多