本文介绍如何在Flutter中创建HTTP网络请求和对请求的json string进行类型解析.

*
网络请求

官方使用的是用dart io中的HttpClient发起的请求,但HttpClient本身功能较弱,很多常用功能都不支持。

建议使用dio <https://github.com/flutterchina/dio> 来发起网络请求,它是一个强大易用的dart
http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载……

 

dart:io 

 

 发起HTTP请求

 

http支持位于dart:io <https://docs.flutter.io/flutter/dart-io/dart-io-library.html>
,所以要创建一个HTTP client, 我们需要添加一个导入:

 
import 'dart:io'; var httpClient = new HttpClient();
 

该 client 支持常用的HTTP操作, such as GET
<https://docs.flutter.io/flutter/dart-io/HttpClient/getUrl.html>, POST
<https://docs.flutter.io/flutter/dart-io/HttpClient/postUrl.html>, PUT
<https://docs.flutter.io/flutter/dart-io/HttpClient/putUrl.html>, DELETE
<https://docs.flutter.io/flutter/dart-io/HttpClient/deleteUrl.html>.

 

处理异步

 

注意,HTTP API 在返回值中使用了Dart Futures
<https://www.dartlang.org/tutorials/language/futures>。 我们建议使用async/await
语法来调用API。

 

网络调用通常遵循如下步骤:

 

* 创建 client.
* 构造 Uri.
* 发起请求, 等待请求,同时您也可以配置请求headers、 body。
* 关闭请求, 等待响应.
* 解码响应的内容.
 

Several of these steps use Future based APIs. Sample APIs calls for each step
above are: 其中的几个步骤使用基于Future的API。上面步骤的示例:

 
get() async { var httpClient = new HttpClient(); var uri = new Uri.http(
'example.com', '/path1/path2', {'param1': '42', 'param2': 'foo'}); var request =
await httpClient.getUrl(uri); var response= await request.close(); var
responseBody= await response.transform(UTF8.decoder).join(); }
dio

添加依赖
dependencies: dio: ^x.x.x // latest version

发起一个 GET 请求 :
Response response; response=await dio.get("/test?id=12&name=wendu")
print(response.data.toString());// 请求参数也可以通过对象传递,上面的代码等同于: response=await
dio.get("/test",data:{"id":12,"name":"wendu"}) print(response.data.toString());
发起一个 POST 请求:
response=await dio.post("/test",data:{"id":12,"name":"wendu"})
发起多个并发请求:
response= await Future.wait([dio.post("/info"),dio.get("/token")]);
下载文件:
response=await dio.download("https://www.google.com/","./xx.html")
发送 FormData:
FormData formData = new FormData.from({ "name": "wendux", "age": 25, });
response= await dio.post("/info", data: formData)
 

通过FormData上传多个文件:
FormData formData = new FormData.from({ "name": "wendux", "age": 25, "file1":
new UploadFileInfo(new File("./upload.txt"), "upload1.txt") "file2": new
UploadFileInfo(new File("./upload.txt"), "upload2.txt") }); response = await
dio.post("/info", data: formData)
*
JSON解析

使用 dart:convert手动序列化JSON

Flutter中基本的JSON序列化非常简单。Flutter有一个内置dart:convert库,其中包含一个简单的JSON编码器和解码器。

以下是一个简单的user model的示例JSON。
{ "name": "John Smith", "email": "[email protected]" }
有了dart:convert,我们可以用两种方式来序列化这个JSON model。我们来看看这两种方法:

内连序列化JSON

通过查看dart:转换JSON文档
<https://api.dartlang.org/stable/1.24.3/dart-convert/JsonCodec-class.html>
,我们发现可以通过调用JSON.decode方法来解码JSON ,使用JSON字符串作为参数。
Map<String, dynamic> user = JSON.decode(json); print('Howdy, ${user['name']}!')
; print('We sent the verification link to ${user['email']}.');
不幸的是,JSON.decode()仅返回一个Map<String, dynamic>,这意味着我们直到运行时才知道值的类型。
通过这种方法,我们失去了大部分静态类型语言特性:类型安全、自动补全和最重要的编译时异常。这样一来,我们的代码可能会变得非常容易出错。

例如,当我们访问name或email
字段时,我们输入的很快,导致字段名打错了。但由于这个JSON在map结构中,所以编译器不知道这个错误的字段名(译者语:所以编译时不会报错)。

在模型类中序列化JSON

我们可以通过引入一个简单的模型类(model class)来解决前面提到的问题,我们称之为User。在User类内部,我们有:

* 一个User.fromJson 构造函数, 用于从一个map构造出一个 User实例 map structure
* 一个toJson 方法, 将 User 实例转化为一个map.
这样,调用代码现在可以具有类型安全、自动补全字段(name和email)以及编译时异常。如果我们将拼写错误或字段视为int类型而不是String,
那么我们的应用程序就不会通过编译,而不是在运行时崩溃。

user.dart
class User { final String name; final String email; User(this.name, this.email)
; User.fromJson(Map<String, dynamic> json) : name = json['name'], email = json[
'email']; Map<String, dynamic> toJson() => { 'name': name, 'email': email, }; }
现在,序列化逻辑移到了模型本身内部。采用这种新方法,我们可以非常容易地反序列化user。
Map userMap = JSON.decode(json); var user = new User.fromJson(userMap); print(
'Howdy,${user.name}!'); print('We sent the verification link to ${user.email}.')
;
要序列化一个user,我们只是将该User对象传递给该JSON.encode方法。我们不需要手动调用toJson这个方法,因为JSON.encode
已经为我们做了。
String json = JSON.encode(user);

Json映射到对象

首先要借助一个工具jsonformat 工具下载地址
<https://github.com/debuggerx01/JSONFormat4Flutter/releases>

举一个例子 json文件 <http://www.wanandroid.com/tree/json>,来自玩安卓网站

这是一个相对很复杂的json文件


用jsonview打开查看,这个json文件包含一个data的数组和两个变量,然后数组的每一项又包含一个数组和6个变量,然后下一级数组的每一项又包含一个数组和6个变量 


下面使用jsonformat 转换成dart bean文件

打开下载的jsonformat ,将json文件copy进去点击格式化 


右边的红色是我们要填写的类名称,对应关系像这样,这里分别填写 tree children children ,后两个相同,点击生成bean 


生成代码如下
import 'dart:convert' show json; class tree { int errorCode; String errorMsg;
List<children> data; tree(jsonStr) {var jsonRes = json.decode(jsonStr);
errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = [];
for (var dataItem in jsonRes['data']){ data.add(new children(dataItem)); } } @
override String toString() {return '{"errorCode": $errorCode,"errorMsg":
${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class
children {int courseId; int id; int order; int parentChapterId; int visible;
String name; List<children> children; children(jsonRes) { courseId = jsonRes[
'courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId =
jsonRes['parentChapterId']; visible = jsonRes['visible']; name = jsonRes[
'name']; children = [];for (var childrenItem in jsonRes['children']){
children.add(new children(childrenItem)); } } @override String toString() {
return'{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId":
$parentChapterId,"visible": $visible,"name": ${name !=
null?'${json.encode(name)}':'null'},"children": $children}'; } } class children
{int courseId; int id; int order; int parentChapterId; int visible; String
name; List<dynamic> children; children(jsonRes) { courseId = jsonRes[
'courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId =
jsonRes['parentChapterId']; visible = jsonRes['visible']; name = jsonRes[
'name']; children = [];for (var childrenItem in jsonRes['children']){
children.add(childrenItem); } } @override String toString() { return
'{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId":
$parentChapterId,"visible": $visible,"name": ${name !=
null?'${json.encode(name)}':'null'},"children": $children}'; } }
接下来就是在APP中请求网络,将其转换成dart bean
///封装的get请求 _networkUtil,可以替换成自己的请求方式 ///发起get网络请求并且转换json Future<dynamic>
requestGet(String url) {return http.get(url) .then((http.Response response) {
final String res = response.body; finalint statusCode = response.statusCode; if
(statusCode <200 || statusCode > 400 || json == null) { throw new Exception(
"Error while fetching data"); }///有值 return _decoder.convert(res); }); }
///这里返回的就是 Future<Tree> 对象,(fillUrl(TREE_LIST)是请求的url Future<Tree> fetchTree() {
return _networkUtil.requestGet(fillUrl(TREE_LIST)).then((dynamic res) {///可以这样取值
returnnew Tree.map(res); }); }  

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信