介绍
应用经常需要执行POST
和GET
其他HTTP请求。
Flutter 提供了一个支持发出 HTTP 请求的http
包。
在本文中,您将创建一个示例 Flutter 应用程序,该应用程序使用该http
包执行 HTTP 请求以显示占位符信息。
先决条件
要完成本教程,您需要:
- 下载并安装Flutter。
- 下载并安装Android Studio 或 Visual Studio Code。
- 建议为您的代码编辑器安装插件:
本教程通过 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
在您的代码编辑器中打开并添加以下插件:
dependencies:
flutter:
sdk: flutter
http: ^0.12.0+2
这是一个由dart.dev发布的官方 Flutter 插件,它具有100% 的健康评分,因此,您可以信任该插件的可靠性。
第 2 步 – 处理GET
请求
您的第一个任务是创建一个可用于与 API 交互的类。
打开您的代码编辑器并http_service.dart
在lib
目录中创建一个文件。在这里,您将开发一个新HttpService
类并添加一个getPosts
函数:
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 占位符。此代码在字符串上使用http
包。get
postsURL
如果该请求成功,此代码将返回List<Post>
using Post.fromJson
。否则,将抛出错误消息。
注意: HTTP 状态代码用于确定请求是成功还是失败。状态代码200
表示成功的 HTTP 请求。
然后,使用您的代码编辑器post_model.dart
在lib
目录中创建一个文件。在这里,您将开发一个新Post
类:
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从占位符的响应,该代码将返回一个新的Post
与fromJson
基于一个JSON方法Map
。
注意:在生产应用程序中,json_serializable
可以使用类似的包来自动处理序列化。
一个Post
返回的JSON占位符将包括的userId
,id
,title
,和body
。
第 3 步 – 显示 Posts
接下来,使用您的代码编辑器posts.dart
在lib
目录中创建一个文件。在这里,您将创建一个PostsPage
类,该类将显示Posts
从 HTTP 请求返回到 JSON 占位符的内容:
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.hasData
是false
,则CircularProgressIndicator
显示 。否则,将ListTile
显示 with post 信息。
为了观察您目前拥有的内容,您需要替换main.dart
.
lib/main.dart
在您的代码编辑器中打开并修改它以使用PostsPage
:
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 列表。
注意:标题将摘自Lorem Ipsum,它经常用作占位符文本。
下一步是创建一个详细页面,当用户单击帖子标题时,其中包含有关帖子的更多信息。
第 4 步 — 显示 PostDetail
如果用户点击帖子,您的应用程序应该将用户导航到一个PostDetail
页面。
使用您的代码编辑器post_detail.dart
在lib
目录中创建一个文件。在这里,您将创建一个PostDetail
显示个人的类Post
:
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}"),
),
],
),
),
],
),
),
)
);
}
}
此代码将显示title
,id
,body
,和userId
。
为了观察您到目前为止所拥有的内容,您需要修改posts.dart
以支持post_detail.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());
}
},
),
);
}
}
编译你的代码并让它在模拟器中运行:
下一步是添加通过删除帖子来删除帖子的功能。
第 5 步 – 处理DELETE
请求
HTTP 请求的另一个示例是DELETE
方法的使用。
http_service.dart
在您的代码编辑器中重新访问并创建一个deletePost(int id)
方法:
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
你的代码编辑器和添加IconButton
到actions
阵内AppBar
。当按下图标时,应删除关联的帖子:
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 中看到一个删除图标按钮。按下按钮将在控制台中打印一条消息:
Outputflutter: DELETED
这将代表一个删除请求。由于 JSON Placeholder 和本示例应用程序的限制,实际上不会删除该帖子。
结论
在本文中,您学习了如何与 Flutterhttp
包进行交互。这允许您GET
查看帖子列表和DELETE
单个帖子。
类似的操作,如post
,put
,patch
,等也可提供。有关更多信息,请参阅官方文档。