The author | | vlad source vlad (public number: fulade_me)

An asynchronous request

Many times in mobile development we rely on asynchronous requests for data and then refreshing the UI. When the user opens the interface, a Loading prompt is given first. After the data request is completed, the data is displayed on the page. This is a common operation.

The advantage of asynchronous requests is that they don’t block the main thread, so the page doesn’t get stuck while the user is “waiting.” Synchronous requests are not suitable for this situation, because the page freezes in synchronous requests, and the user cannot click (even if the click does not work), and the experience is very bad. So most of the time we use asynchronous requests to get data

HTTP library

Flutter allows you to make web requests using the HTTP library. It supports asynchronous requests and has a good API to use the HTTP library steps:

  • In the project, openpubspec.yamlfile
  • finddependenciesField, add belowHTTP: ^ 0.12.2, including0.12.2Is the version number
  • And then savepubspec.yamlAnd performpub getCommand to download the third party library we will use

The specific use of the pub get command was described in a previous article

Then introduce the header file in the file that you want to use the HTTP library

import 'package:http/http.dart' as http;
Copy the code

The code to send the HTTP request is also relatively simple, using the GET request as an example

http.get("https://cdn.jsdelivr.net/gh/johnson8888/blog_pages/images/request_demo_test.json");
Copy the code

Just pass in the URL to request, and in this case the URL is the test file I uploaded myself.

The result of the HTTP asynchronous request is returned

I know that the HTTP library supports asynchronous requests, so how do we receive the results of asynchronous requests?

  • throughthenFunction gets atgetWe can follow the request directlythenFunction as a callback, within which the result of the request can be retrieved
http.get(getURL).then((value) {
  print(value);
});
Copy the code

This is handy, but when we have a lot of network requests and one network request depends on another, multiple callback functions are nested together (aka callback hell) and the code is messy and not good for debugging.

  • useawaitTo receive the results of an asynchronous operation
var data = await http.get(getURL);
Copy the code

This is much cleaner to write than the above code, but it is important to note that if a function has an await method inside it, the function should be async and the return value should be Future, which is an object that is delayed to evaluate, The exact value of the Future is retrieved only when the function being await returns. Example below:

Future<Map> getData() async {
  var data = await http.get(getURL);
  return data.body; 
}
Copy the code

Refresh the page

We already know that calling setState() can refresh the page, so we can refresh the page by calling setState() after the HTTP request

http.get(getURL).then((value) {
  print(value);
  var data = jsonDecode(data.body);
  setState(() {
    /// The code to refresh the page is executed here
  });
});
Copy the code

Use FutureBuilder to refresh the page

Of course, setState() can refresh the page, but when we have multiple network requests on the page, we will constantly call setState() to refresh the page, which is obviously a bit redundant. Flutter provides us with a better way to retrieve data and refresh the UI. That is, FutureBuilder looks at its initialization method

const FutureBuilder({
  /// key
  Key key,
  /// Asynchronous operation
  this.future,
  /// Initialize data
  this.initialData,
  /// The function that builds the UI
  @required this.builder,
}) 
Copy the code

As you can see from the constructor, we need to pass in the future argument, which is our time consuming manipulation function, The builder method captures two arguments: BuildContext Context and AsyncSnapshot snap. The snap property will carry the return value of the future’s time-consuming function. After the time-consuming operation function returns the result, we can get the return value in the Builder method. So we can also implement the above request like this:

FutureBuilder(
  future: getData(),
  builder: (BuildContext context, AsyncSnapshot snap) {
    /// If there is no data, we display the loading page
    if (snap.hasData == false) {
      return CircularProgressIndicator();
    } else {
    /// If we get the data we initialize a ListView to display the data that we got
      var dataSource = snap.data["tracks"];
      return ListView.builder(
        itemCount: dataSource.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(dataSource[index]["title"]),
            subtitle: Text(dataSource[index]["cover"])); }); }}),Copy the code

After we get the data, we build a ListView through ListView.builder and return, and we’re done refreshing the UI

I’m keeping it simple here, but there’s a more elegant way to use hasData as a basis: use another snap property, connectionState

enum ConnectionState {
  /// There are no asynchronous tasks,
  none,
  /// Asynchronous tasks are waiting
  waiting,
  /// An asynchronous task is being executed or data is being transferred
  active,
  /// The asynchronous task has terminated.
  done,
}
Copy the code

We can also check if there is any data when the connectionState is done and display it if there is!

To see how the above example works, go to my Github repository project flutter_app->lib->routes->http_page.dart and download it and run it.