简介
应用程序经常需要执行POST
和GET
等HTTP请求。
Ffltter提供了支持发起Http请求的HTTP
包。
在本文中,您将创建一个示例Flutter应用程序,该应用程序使用http
包执行HTTP请求以显示占位符信息。
前提条件
要完成本教程,您需要:
- 下载并安装Flutter。
- 下载并安装Android Studio或 Visual Studio Code。
- 建议为您的代码编辑器安装插件:
本教程已通过Flutter v1.22.2、Android SDK v30.0.2和Android Studio v4.1验证。
第一步-设置项目
为了按照设置进行操作,您将创建一个示例颤动应用程序。
将环境设置为颤动后,可以运行以下命令来创建新应用程序:
1flutter create flutter_http_example
导航到新项目目录:
1cd flutter_http_example
使用fltter create
将生成一个演示应用程序,其中将显示按钮被点击的次数。
在代码编辑器中打开pubspec.yaml
,添加如下插件:
1[label pubspec.yaml]
2dependencies:
3 flutter:
4 sdk: flutter
5
6 http: ^0.12.0+2
这是一个由dart.dev发布的官方扑翼插件,它有100%健康得分,),因此,你可以相信这个插件的可靠性。
第二步-处理GET
请求
您的第一个任务将是创建一个可用于与API交互的类。
打开代码编辑器,在lib
目录下创建一个http_service.dart
文件。这里,您将开发一个新的HttpService
类,并添加一个getPosts
函数:
1[label lib/http_service.dart]
2import 'dart:convert';
3import 'package:http/http.dart';
4import 'post_model.dart';
5
6class HttpService {
7 final String postsURL = "https://jsonplaceholder.typicode.com/posts";
8
9 Future<List<Post>> getPosts() async {
10 Response res = await get(postsURL);
11
12 if (res.statusCode == 200) {
13 List<dynamic> body = jsonDecode(res.body);
14
15 List<Post> posts = body
16 .map(
17 (dynamic item) => Post.fromJson(item),
18 )
19 .toList();
20
21 return posts;
22 } else {
23 throw "Unable to retrieve posts.";
24 }
25 }
26}
在本例中,您将连接到JSON Placeholder。这段代码使用http
包的get
对postsURL
字符串。
如果请求成功,此代码将使用Post.from Json
返回List<Post>
。否则,将抛出一条错误消息。
<$>[备注]
注意: http状态code用于判断请求是否成功。状态码200
表示HTTP请求成功。
<$>
然后,使用您的代码编辑器在lib
目录中创建一个post_Model.dart
文件。在这里,您将开发一个新的Post
类:
1[label lib/post_model.dart]
2import 'package:flutter/foundation.dart';
3
4class Post {
5 final int userId;
6 final int id;
7 final String title;
8 final String body;
9
10 Post({
11 @required this.userId,
12 @required this.id,
13 @required this.title,
14 @required this.body,
15 });
16
17 factory Post.fromJson(Map<String, dynamic> json) {
18 return Post(
19 userId: json['userId'] as int,
20 id: json['id'] as int,
21 title: json['title'] as String,
22 body: json['body'] as String,
23 );
24 }
25}
为了序列化来自JSON占位符的响应,此代码将返回一个新的Post
,该Post
带有基于JSONMap
的FromJson
方法。
<$>[备注]
注意: 在生产应用程序中,可以使用像json_serializable
这样的包来自动处理序列化。
<$>
JSON占位符返回的Post
由userId
、id
、tile
、body
组成。
第三步-显示Posts
接下来,使用代码编辑器在lib
目录中创建一个posts.dart
文件。在这里,您将创建一个PostsPage
类,它将显示从对JSON占位符的HTTP请求返回的Posts
:
1[label lib/posts.dart]
2import 'package:flutter/material.dart';
3import 'http_service.dart';
4import 'post_model.dart';
5
6class PostsPage extends StatelessWidget {
7 final HttpService httpService = HttpService();
8
9 @override
10 Widget build(BuildContext context) {
11 return Scaffold(
12 appBar: AppBar(
13 title: Text("Posts"),
14 ),
15 body: FutureBuilder(
16 future: httpService.getPosts(),
17 builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
18 if (snapshot.hasData) {
19 List<Post> posts = snapshot.data;
20 return ListView(
21 children: posts
22 .map(
23 (Post post) => ListTile(
24 title: Text(post.title),
25 subtitle: Text("${post.userId}"),
26 ),
27 )
28 .toList(),
29 );
30 } else {
31 return Center(child: CircularProgressIndicator());
32 }
33 },
34 ),
35 );
36 }
37}
此代码使用FutureBuilder
小部件与getPosts()
函数交互。这允许代码确定List
何时
如果Snaphot.hasData
为False
,则显示CircularProgressIndicator
。否则,显示带有帖子信息的ListTile
。
为了观察到目前为止的情况,您需要替换main.dart
中的代码。
在代码编辑器中打开lib/main.dart
,修改为使用PostsPage
:
1[label lib/main.dart]
2import 'package:flutter/material.dart';
3import 'posts.dart';
4
5void main() {
6 runApp(MyApp());
7}
8
9class MyApp extends StatelessWidget {
10 @override
11 Widget build(BuildContext context) {
12 return MaterialApp(
13 title: 'HTTP',
14 debugShowCheckedModeBanner: false,
15 theme: ThemeData(
16 primarySwatch: Colors.blue,
17 visualDensity: VisualDensity.adaptivePlatformDensity,
18 ),
19 home: PostsPage(),
20 );
21 }
22}
编译代码并让其在模拟器中运行:
返回的帖子标题和用户ID的列表
您应该看到JSON占位符返回的帖子标题和用户ID的列表。
<$>[备注] 注: 标题摘录自lorem Ipsum,经常用作占位符文本。 <$>
下一步是创建一个详细页面,当用户点击帖子标题时,该页面包含有关该帖子的更多信息。
第四步-展示PostDetail
如果用户点击了帖子,你的应用程序应该会将用户导航到一个PostDetail
页面。
使用您的代码编辑器在lib
目录中创建一个post_Detail.dart
文件。这里,您将创建一个PostDetail
类,它将显示一个单独的Post
:
1[label lib/post_detail.dart]
2import 'package:flutter/material.dart';
3import 'post_model.dart';
4
5class PostDetail extends StatelessWidget {
6 final Post post;
7
8 PostDetail({@required this.post});
9
10 @override
11 Widget build(BuildContext context) {
12 return Scaffold(
13 appBar: AppBar(
14 title: Text(post.title),
15 ),
16 body: SingleChildScrollView(
17 child: Padding(
18 padding: const EdgeInsets.all(12.0),
19 child: Column(
20 children: <Widget>[
21 Card(
22 child: Column(
23 crossAxisAlignment: CrossAxisAlignment.center,
24 children: <Widget>[
25 ListTile(
26 title: Text("Title"),
27 subtitle: Text(post.title),
28 ),
29 ListTile(
30 title: Text("ID"),
31 subtitle: Text("${post.id}"),
32 ),
33 ListTile(
34 title: Text("Body"),
35 subtitle: Text(post.body),
36 ),
37 ListTile(
38 title: Text("User ID"),
39 subtitle: Text("${post.userId}"),
40 ),
41 ],
42 ),
43 ),
44 ],
45 ),
46 ),
47 )
48 );
49 }
50}
此代码将显示tile
、id
、body
和userId
。
为了观察到目前为止的情况,您需要修改posts.dart
以支持post_Detail.dart
:
1[label lib/posts.dart]
2import 'package:flutter/material.dart';
3import 'http_service.dart';
4import 'post_detail.dart';
5import 'post_model.dart';
6
7class PostsPage extends StatelessWidget {
8 final HttpService httpService = HttpService();
9
10 @override
11 Widget build(BuildContext context) {
12 return Scaffold(
13 appBar: AppBar(
14 title: Text("Posts"),
15 ),
16 body: FutureBuilder(
17 future: httpService.getPosts(),
18 builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
19 if (snapshot.hasData) {
20 List<Post> posts = snapshot.data;
21 return ListView(
22 children: posts
23 .map(
24 (Post post) => ListTile(
25 title: Text(post.title),
26 subtitle: Text("${post.userId}"),
27 onTap: () => Navigator.of(context).push(
28 MaterialPageRoute(
29 builder: (context) => PostDetail(
30 post: post,
31 ),
32 ),
33 ),
34 ),
35 )
36 .toList(),
37 );
38 } else {
39 return Center(child: CircularProgressIndicator());
40 }
41 },
42 ),
43 );
44 }
45}
编译你的代码并让它在模拟器中运行:
返回的单个帖子的详细信息
下一步是添加通过删除帖子来删除帖子的功能。
第五步-处理DELETE
请求
另一个HTTP请求的例子是使用DELETE
方法。
在代码编辑器中重新访问http_service.dart
,并创建一个deletePost(Int Id)
方法:
1[label lib/http_service.dart]
2import 'dart:convert';
3import 'package:http/http.dart';
4import 'post_model.dart';
5
6class HttpService {
7 final String postsURL = "https://jsonplaceholder.typicode.com/posts";
8
9 // ...
10
11 Future<void> deletePost(int id) async {
12 Response res = await delete("$postsURL/$id");
13
14 if (res.statusCode == 200) {
15 print("DELETED");
16 } else {
17 throw "Unable to delete post.";
18 }
19 }
20}
在代码编辑器中重新访问post_Detail.dart
,并在AppBar
内的actions
数组中添加一个IconButton
。当按下图标时,关联的帖子应被删除:
1[label lib/post_detail.dart]
2import 'package:flutter/material.dart';
3import 'http_service.dart';
4import 'post_model.dart';
5
6class PostDetail extends StatelessWidget {
7 final HttpService httpService = HttpService();
8 final Post post;
9
10 PostDetail({@required this.post});
11
12 @override
13 Widget build(BuildContext context) {
14 return Scaffold(
15 appBar: AppBar(
16 title: Text(post.title),
17 actions: <Widget>[
18 IconButton(
19 icon: Icon(Icons.delete),
20 onPressed: () async {
21 await httpService.deletePost(post.id);
22 Navigator.of(context).pop();
23 },
24 )
25 ],
26 ),
27 // ...
28 );
29 }
30}
编译代码并让其在模拟器中运行。
当您访问帖子详情页时,您会在AppBar中看到一个删除 图标按钮。按下按钮将在控制台中打印一条消息:
1[secondary_label Output]
2flutter: DELETED
这将表示一个删除请求。由于JSON占位符和这个示例应用程序的限制,该帖子实际上不会被删除。
结论
在本文中,您学习了如何与Flutter http
包进行交互。这允许你获取
一个帖子列表和删除
一个单独的帖子。
也支持post
、put
、patch
等类似操作。更多信息,请咨询官方documentation。