如何在 Flutter 中使用 HTTP 请求

介绍

应用经常需要执行POSTGET其他HTTP请求。

Flutter 提供了一个支持发出 HTTP 请求http

在本文中,您将创建一个示例 Flutter 应用程序,该应用程序使用该http包执行 HTTP 请求以显示占位符信息。

先决条件

要完成本教程,您需要:

本教程通过 Flutter v1.22.2、Android SDK v30.0.2、Android Studio v4.1 验证。

步骤 1 — 设置项目

为了进行设置,您将创建一个示例 Flutter 应用程序。

为 Flutter 设置环境后,您可以运行以下命令来创建新应用程序:

  • flutter create flutter_http_example

导航到新的项目目录:

  • cd flutter_http_example

使用flutter create将生成一个演示应用程序,该应用程序将显示单击按钮的次数。

pubspec.yaml在您的代码编辑器中打开并添加以下插件:

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  http: ^0.12.0+2

这是一个由dart.dev发布的官方 Flutter 插件,它具有100% 的健康评分,因此,您可以信任该插件的可靠性。

第 2 步 – 处理GET请求

您的第一个任务是创建一个可用于与 API 交互的类。

打开您的代码编辑器并http_service.dartlib目录中创建一个文件在这里,您将开发一个新HttpService类并添加一个getPosts函数:

lib/http_service.dart
import 'dart:convert';
import 'package:http/http.dart';
import 'post_model.dart';

class HttpService {
  final String postsURL = "https://jsonplaceholder.typicode.com/posts";

  Future<List<Post>> getPosts() async {
    Response res = await get(postsURL);

    if (res.statusCode == 200) {
      List<dynamic> body = jsonDecode(res.body);

      List<Post> posts = body
        .map(
          (dynamic item) => Post.fromJson(item),
        )
        .toList();

      return posts;
    } else {
      throw "Unable to retrieve posts.";
    }
  }
}

在此示例中,您将连接到 JSON 占位符。此代码字符串使用httpgetpostsURL

如果该请求成功,此代码将返回List<Post>using Post.fromJson否则,将抛出错误消息。

注意: HTTP 状态代码用于确定请求是成功还是失败。状态代码200表示成功的 HTTP 请求。

然后,使用您的代码编辑器post_model.dartlib目录中创建一个文件在这里,您将开发一个新Post类:

lib/post_model.dart
import 'package:flutter/foundation.dart';

class Post {
  final int userId;
  final int id;
  final String title;
  final String body;

  Post({
    @required this.userId,
    @required this.id,
    @required this.title,
    @required this.body,
  });

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      userId: json['userId'] as int,
      id: json['id'] as int,
      title: json['title'] as String,
      body: json['body'] as String,
    );
  }
}

为了序列化JSON从占位符的响应,该代码将返回一个新的PostfromJson基于一个JSON方法Map

注意:在生产应用程序中,json_serializable可以使用类似的包来自动处理序列化。

一个Post返回的JSON占位符将包括的userIdidtitle,和body

第 3 步 – 显示 Posts

接下来,使用您的代码编辑器posts.dartlib目录中创建一个文件在这里,您将创建一个PostsPage类,该类将显示Posts从 HTTP 请求返回到 JSON 占位符的内容:

lib/posts.dart
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_model.dart';

class PostsPage extends StatelessWidget {
  final HttpService httpService = HttpService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Posts"),
      ),
      body: FutureBuilder(
        future: httpService.getPosts(),
        builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
          if (snapshot.hasData) {
            List<Post> posts = snapshot.data;
            return ListView(
              children: posts
                  .map(
                    (Post post) => ListTile(
                      title: Text(post.title),
                      subtitle: Text("${post.userId}"),
                    ),
                  )
                  .toList(),
            );
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

此代码使用FutureBuilder小部件与getPosts()函数进行交互这允许代码确定何时List<Post>准备就绪并采取相应的行动。

如果snapshot.hasDatafalse,则CircularProgressIndicator显示 。否则,将ListTile显示 with post 信息。

为了观察您目前拥有的内容,您需要替换main.dart.

lib/main.dart在您的代码编辑器中打开并修改它以使用PostsPage

lib/main.dart
import 'package:flutter/material.dart';
import 'posts.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HTTP',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: PostsPage(),
    );
  }
}

编译你的代码并让它在模拟器中运行:

显示由 JSON Placeholder 返回的帖子标题和用户 ID 列表的应用程序当前状态的屏幕截图

您应该观察 JSON Placeholder 返回的帖子标题和用户 ID 列表。

注意:标题将摘自Lorem Ipsum,它经常用作占位符文本。

下一步是创建一个详细页面,当用户单击帖子标题时,其中包含有关帖子的更多信息。

第 4 步 — 显示 PostDetail

如果用户点击帖子,您的应用程序应该将用户导航到一个PostDetail页面。

使用您的代码编辑器post_detail.dartlib目录中创建一个文件在这里,您将创建一个PostDetail显示个人的类Post

lib/post_detail.dart
import 'package:flutter/material.dart';
import 'post_model.dart';

class PostDetail extends StatelessWidget {
  final Post post;

  PostDetail({@required this.post});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(post.title),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(12.0),
          child: Column(
            children: <Widget>[
              Card(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    ListTile(
                      title: Text("Title"),
                      subtitle: Text(post.title),
                    ),
                    ListTile(
                      title: Text("ID"),
                      subtitle: Text("${post.id}"),
                    ),
                    ListTile(
                      title: Text("Body"),
                      subtitle: Text(post.body),
                    ),
                    ListTile(
                      title: Text("User ID"),
                      subtitle: Text("${post.userId}"),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      )
    );
  }
}

此代码将显示titleidbody,和userId

为了观察您到目前为止所拥有的内容,您需要修改posts.dart以支持post_detail.dart

lib/posts.dart
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_detail.dart';
import 'post_model.dart';

class PostsPage extends StatelessWidget {
  final HttpService httpService = HttpService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Posts"),
      ),
      body: FutureBuilder(
        future: httpService.getPosts(),
        builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
          if (snapshot.hasData) {
            List<Post> posts = snapshot.data;
            return ListView(
              children: posts
                  .map(
                    (Post post) => ListTile(
                      title: Text(post.title),
                      subtitle: Text("${post.userId}"),
                      onTap: () => Navigator.of(context).push(
                        MaterialPageRoute(
                          builder: (context) => PostDetail(
                            post: post,
                          ),
                        ),
                      ),
                    ),
                  )
                  .toList(),
            );
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

编译你的代码并让它在模拟器中运行:

显示由 JSON Placeholder 返回的单个帖子的详细信息的应用程序当前状态的屏幕截图

下一步是添加通过删除帖子来删除帖子的功能。

第 5 步 – 处理DELETE请求

HTTP 请求的另一个示例是DELETE方法的使用

http_service.dart在您的代码编辑器中重新访问并创建一个deletePost(int id)方法:

lib/http_service.dart
import 'dart:convert';
import 'package:http/http.dart';
import 'post_model.dart';

class HttpService {
  final String postsURL = "https://jsonplaceholder.typicode.com/posts";

  // ...

  Future<void> deletePost(int id) async {
    Response res = await delete("$postsURL/$id");

    if (res.statusCode == 200) {
      print("DELETED");
    } else {
      throw "Unable to delete post.";
    }
  }
}

重温post_detail.dart你的代码编辑器和添加IconButtonactions阵内AppBar当按下图标时,应删除关联的帖子:

lib/post_detail.dart
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_model.dart';

class PostDetail extends StatelessWidget {
  final HttpService httpService = HttpService();
  final Post post;

  PostDetail({@required this.post});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(post.title),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: () async {
              await httpService.deletePost(post.id);
              Navigator.of(context).pop();
            },
          )
        ],
      ),
      // ...
    );
  }
}

编译您的代码并让它在模拟器中运行。

当您访问帖子详细信息页面时,您将在 AppBar 中看到一个删除图标按钮。按下按钮将在控制台中打印一条消息:

Output
flutter: DELETED

这将代表一个删除请求。由于 JSON Placeholder 和本示例应用程序的限制,实际上不会删除该帖子。

结论

在本文中,您学习了如何与 Flutterhttp进行交互这允许您GET查看帖子列表和DELETE单个帖子。

类似的操作,如postputpatch,等也可提供。有关更多信息,请参阅官方文档

觉得文章有用?

点个广告表达一下你的爱意吧 !😁