从大多数应用程序都需要从互联网上获取数据,Dart和Flutter提供了相关工具!

注:本篇示例官方使用的是用http package发起简单的网络请求,但是http package功能较弱,很多常用功能都不支持。我们建议您使用dio 来发起网络请求,它是一个强大易用的dart http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载……详情请查看github dio .

步骤

  1. 1. 添加`http` package依赖
  2. 2. 使用`http` package发出网络请求
  3. 3. 将响应转为自定义的Dart对象
  4. 4. 获取并显示数据

1. 添加http package

http package提供了从互联网获取数据的最简单方法。

  1. dependencies:
  2. http: <latest_version>

2. 发起网络请求

在这个例子中,我们将使用http.getJSONPlaceholder REST API中获取示例文章。

  1. Future<http.Response> fetchPost() {
  2. return http.get('https://jsonplaceholder.typicode.com/posts/1');
  3. }

http.get方法返回一个包含一个ResponseFuture

  • Future是与异步操作一起工作的核心Dart类。它用于表示未来某个时间可能会出现的可用值或错误。
  • http.Response类包含一个成功的HTTP请求接收到的数据

3. 将响应转换为自定义Dart对象

虽然发出网络请求很简单,但如果要使用原始的Future<http.Response>并不简单。为了让我们可以开开心心的写代码,我们可以将http.Response转换成我们自己的Dart对象。

创建一个Post

首先,我们需要创建一个Post类,它包含我们网络请求的数据。它还将包括一个工厂构造函数,它允许我们可以通过json创建一个Post对象。

手动转换JSON只是一种选择。有关更多信息,请参阅关于JSON和序列化的完整文章。

  1. class Post {
  2. final int userId;
  3. final int id;
  4. final String title;
  5. final String body;
  6. Post({this.userId, this.id, this.title, this.body});
  7. factory Post.fromJson(Map<String, dynamic> json) {
  8. return new Post(
  9. userId: json['userId'],
  10. id: json['id'],
  11. title: json['title'],
  12. body: json['body'],
  13. );
  14. }
  15. }

http.Response 转换成一个Post对象

现在,我们将更新fetchPost函数以返回一个Future<Post>。为此,我们需要:

  1. 使用dart:convert package将响应内容转化为一个json Map
  2. 使用fromJson工厂函数,将json Map 转化为一个Post对象。
  1. Future<Post> fetchPost() async {
  2. final response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
  3. final json = JSON.decode(response.body);
  4. return new Post.fromJson(json);
  5. }

Hooray! 现在我们有一个函数,我们可以调用它从互联网上获取一篇文章!

4. 获取并显示数据

为了获取数据并将其显示在屏幕上,我们可以使用FutureBuilder widget!FutureBuilder Widget可以很容易与异步数据源一起工作。

我们需要提供两个参数:

  1. future参数是一个异步的网络请求,在这个例子中,我们传递调用fetchPost()函数的返回值(一个future)。

  2. 一个 builder 函数,这告诉Flutter在future执行的不同阶段应该如何渲染界面。

    1. new FutureBuilder<Post>(
    2. future: fetchPost(),
    3. builder: (context, snapshot) {
    4. if (snapshot.hasData) {
    5. return new Text(snapshot.data.title);
    6. } else if (snapshot.hasError) {
    7. return new Text("${snapshot.error}");
    8. }
    9. // By default, show a loading spinner
    10. return new CircularProgressIndicator();
    11. },
    12. );

    译者注:其中snapshot.data即为Future的结果。

完整的例子

  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'package:flutter/material.dart';
  4. import 'package:http/http.dart' as http;
  5. Future<Post> fetchPost() async {
  6. final response =
  7. await http.get('https://jsonplaceholder.typicode.com/posts/1');
  8. final responseJson = json.decode(response.body);
  9. return new Post.fromJson(responseJson);
  10. }
  11. class Post {
  12. final int userId;
  13. final int id;
  14. final String title;
  15. final String body;
  16. Post({this.userId, this.id, this.title, this.body});
  17. factory Post.fromJson(Map<String, dynamic> json) {
  18. return new Post(
  19. userId: json['userId'],
  20. id: json['id'],
  21. title: json['title'],
  22. body: json['body'],
  23. );
  24. }
  25. }
  26. void main() => runApp(new MyApp());
  27. class MyApp extends StatelessWidget {
  28. @override
  29. Widget build(BuildContext context) {
  30. return new MaterialApp(
  31. title: 'Fetch Data Example',
  32. theme: new ThemeData(
  33. primarySwatch: Colors.blue,
  34. ),
  35. home: new Scaffold(
  36. appBar: new AppBar(
  37. title: new Text('Fetch Data Example'),
  38. ),
  39. body: new Center(
  40. child: new FutureBuilder<Post>(
  41. future: fetchPost(),
  42. builder: (context, snapshot) {
  43. if (snapshot.hasData) {
  44. return new Text(snapshot.data.title);
  45. } else if (snapshot.hasError) {
  46. return new Text("${snapshot.error}");
  47. }
  48. // By default, show a loading spinner
  49. return new CircularProgressIndicator();
  50. },
  51. ),
  52. ),
  53. ),
  54. );
  55. }
  56. }