
Flutter中的Http请求和数据转换
大部分的应用开发中都离不开Http请求,因此,我们将研究如何在Flutter中使用http插件。
创建一个新的Flutter项目
为了进行设置,我们将创建一个Flutter应用示例。假设您已经安装了Flutter和Dart SDK,请在终端中运行以下命令:
# 创建Flutter应用
$ flutter create flutter_http
# 在vscode中打开
$ cd flutter_http && code .
添加HTTP插件
切换到您的pubspec.yaml,并添加以下插件:
dependencies:
flutter:
sdk: flutter
http: ^0.12.0+2
这是dart.dev发布的官方Flutter插件,因此,我们可以相信它的可靠性。
HTTP请求
我们的第一个任务是创建一个可用于与API交互的类。我们将在lib/http_service.dart文件中创建一个名为HttpService的新类,并添加一个getPosts函数:
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 "Can't get posts.";
}
}
}
从getPosts函数可以看出,我们首先调用http包上的get方法请求postsURL。
接下来,如果该请求成功,我们将解析响应并使用Post.fromJson返回List <Post>。让我们继续在lib/posts_model.dart中创建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 Map使用fromJson方法返回一个新的帖子。在生产应用程序中,我建议使用json_serializable之类的东西来自动处理序列化。
展示文章
让我们在lib/posts.dart中创建一个名为PostsPage的新页面:
import 'package:flutter/material.dart';
import 'package:flut_http/http_service.dart';
import 'package:flut_http/post_detail.dart';
import 'package:flut_http/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());
}
},
),
);
}
}
我们使用FutureBuilder小部件与getPosts()函数进行交互。这使我们能够确定List<Post>何时准备就绪并采取相应措施。
如果snapshot.hasData为false,则显示的是CircularProgressIndicator,否则显示的是带有各种发布信息的ListTile。
确保把main.dart中主页的home属性设置为PostsPage:
import 'package:flutter/material.dart';
import 'package:flut_http/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.deepPurple,
),
home: PostsPage(),
);
}
}

文章详情
如果用户点击该帖子,我们希望将其导航到PostDetail页面。让我们来构建它:
import 'package:flutter/material.dart';
import 'package:flut_http/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}"),
),
],
),
),
],
),
),
));
}
}
虽然此页面没有任何HTTP数据,但我选择了一些字段数据用来模拟显示完整的Post。

删除
HTTP请求的另一个示例是delete方法的使用。例如,在我们的HttpService内部,我们可以创建一个deletePost(int id)方法:
Future<void> deletePost(int id) async {
Response res = await delete("$postsURL/$id");
if (res.statusCode == 200) {
print("DELETED");
} else {
throw "Can't delete post.";
}
}
我们可以在AppBar的actions数组中添加一个IconButton,每当点击它时,都会删除一个Post:
final HttpService httpService = HttpService();
@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();
},
)
],
),
//
)
}
最后
在本文中,我们研究了如何与Flutter http软件包进行交互。这使我们能够获取文章列表,以及删除单个文章。也可以使用其他操作,如发布,修改等。