Flutter - Is it possible to extract data from a Future without using a FutureBuilder?

↘锁芯ラ 提交于 2020-12-29 09:02:53

问题


I'm reading in user-provided input (in this case a zip code) from a TextField that I need to check against a database for validity. However, I need to make an asynchronous database query inside of the submit button's (a RaisedButton in this case) onPressed: () {} lambda function. In most programming languages, this is a fairly straightforward and simple task. The problem I'm running into in Flutter, however, is the fact that Future objects returned from asynchronous database queries can only be consumed by FutureBuilder objects which in turn only return Widget objects. I simply need a String returned that I can then use to either pass to a new route via a MaterialPageRoute object, or display an error to the user without changing routes. Is there any way to do this with Flutter? Returning a Widget is useless to me as I don't want to create a new Widget for display. I am using Flutter 0.3.2 and Dart 2.0.0

As a simplified example of where I need to call the database query:

@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
                        }
                    }
                }
            ),
        ],
    );
}

Perhaps I'm not following the "mantra" of Flutter? I appreciate your consideration and input on this.


回答1:


FutureBuilder is just a convenient helper to get the widget tree rebuilt when a Future completes.

You can use

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

or

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

The main limitation is that you can't return the value directly to the caller without a Future, because there is no way to get back from async execution to sync execution.




回答2:


I've since figured this out (I believe this is what Günter was originally saying, but the fundamental reason why wasn't clear to me at the time). The only way to be able to consume a Future without creating a Widget object is by using the Future API. The Future API allows the parsing of a Future object as though it was an AsyncSnapshot object (which is where one would parse .data in a FutureBuilder builder: function). This can be performed on a returned Future object (which can use async with await). For example:

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);
   });

This is rather simple once you understand how the Future API can be leveraged, and it's intent vs. using FutureBuilder. Good to know for newbies of this language such as myself!




回答3:


A Future is just semantic sugar for a callback. Imagine you had:

void fetchName(void Function(String) callback);

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

There isn't a way to convert (or extract) name from fetchName. It doesn't exist until the callback is completed, and the callback may not be completed immediately (could be read from a database, like your example, or the network, etc).

One of the advantages of using FutureBuilder is it really helps make sense of asynchronous abstractions like Future (and StreamBuilder for Stream), and let you focus on writing (synchronous) builder code:

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}');
    }
  },
)



回答4:


you can create two methods, one to extract data which you put in a variable and another as like getter (In my case I need to access secure value with plugin flutter_secure_storage without using 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;
}
}


来源:https://stackoverflow.com/questions/50296061/flutter-is-it-possible-to-extract-data-from-a-future-without-using-a-futurebui

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!