Flutter 陈航 24-网络编程 http dio JSON 反射
目录
24 | HTTP网络编程与JSON解析
Flutter 中,Http 网络编程的实现方式主要分为三种:
- HttpClient
- Dart 原生
http
请求库 - 第三方库
dio
HttpClient
HttpClient 是 dart:io
库中提供的网络请求类,实现了基本的网络编程功能。
testGetUrl() async {
HttpClient httpClient = HttpClient();
httpClient.idleTimeout = const Duration(seconds: 5);
Uri uri = Uri.parse("https://storage.flutter-io.cn");
HttpClientRequest request = await httpClient.getUrl(uri);
request.headers.add("user-agent", "Custom-UA");
// 发起请求,等待响应
HttpClientResponse response = await request.close();
// 收到响应,打印结果
if (response.statusCode == HttpStatus.ok) {
var text = await response.transform(utf8.decoder).join();
flog(text);
} else {
flog('Error: statusCode = ${response.statusCode}');
}
}
http
http 是 Dart 官方提供的另一个网络请求类,相比于 HttpClient 更加简单。
dependencies:
http: ^0.13.5
import 'package:http/http.dart' as http;
testGetUrl() async {
http.Response response = await http.Client().get(
Uri.parse("https://storage.flutter-io.cn"),
headers: {"user-agent": "Custom-UA"},
);
if (response.statusCode == HttpStatus.ok) {
flog(response.body);
} else {
flog("Error: ${response.statusCode}");
}
}
dio
HttpClient 和 http 暴露的定制化能力都相对较弱,很多常用的功能都不支持,比如取消请求、定制拦截器、Cookie 管理等。因此对于复杂的网络请求行为,推荐使用目前在 Dart 社区人气较高的 dio 来发起网络请求。
dependencies:
dio: ^5.0.1
testGetUrl() async {
var response = await Dio().get(
"https://storage.flutter-io.cn",
options: Options(headers: {"user-agent": "Custom-UA"}),
);
if (response.statusCode == HttpStatus.ok) {
flog(response.data.toString());
} else {
flog("Error: ${response.statusCode}");
}
}
dio.get
方法的options
参数提供了精细化控制网络请求的能力,可以支持设置 Header、超时时间、Cookie、请求方法等。
- 文件下载:可以使用
download
方法实现 - 文件上传:可以通过构建表单
FormData
实现 - 并行请求:可以结合
Future.wait
方法实现 - 拦截器:提供了与 okHttp 一样的拦截器,可以在请求前或响应后做一些特殊的操作
JSON 解析
不支持运行时反射
在 Flutter 中,没有像原生开发那样提供了 Gson 或 Mantle 等库,用于将 JSON 字符串直接转换为对应的实体类。而这些能力无一例外都需要用到运行时反射,这是 Flutter 从设计之初就不支持的,理由如下:
- 运行时反射破坏了类的封装性和安全性,会带来安全风险
- 运行时反射会增加二进制文件大小。使用反射后,因为不清楚哪些代码可能会在运行时用到,因此会默认使用所有代码构建应用程序,这就导致编译器无法优化编译期间未使用的代码,应用安装包体积无法进一步压缩。
解析案例
String jsonString = '''
{
"name":"张三",
"score" : 95,
"teacher": {
"name": "李四",
"age" : 40
}
}
''';
- 首先根据 JSON 结构定义 Student 类、Teacher 类
- 并创建对应的解析工厂类,来处理属性与字典之间的映射关系
class Student {
String name;
int score;
Teacher teacher;
Student({required this.name, required this.score, required this.teacher});
// JSON 解析工厂类,使用字典数据为对象初始化赋值
factory Student.fromJson(Map<String, dynamic> parsedJson) {
return Student(
name: parsedJson['name'],
score: parsedJson['score'],
teacher: Teacher.fromJson(parsedJson['teacher']),
);
}
}
class Teacher {
String name;
int age;
Teacher({required this.name, required this.age});
factory Teacher.fromJson(Map<String, dynamic> parsedJson) {
return Teacher(name: parsedJson['name'], age: parsedJson['age']);
}
}
- 把 JSON 字符串通过
json.decode
方法转换成 Map - 然后把它交给工厂类的 fromJson 方法,即可完成 Student 对象的解析
loadStudent() {
final jsonResponse = json.decode(jsonString);
Student student = Student.fromJson(jsonResponse);
flog("${student.name} - ${student.score} - ${student.teacher.name} - ${student.teacher.age}");
}
对于这类 CPU 密集型的操作,可以使用 compute 函数,将解析工作放到新的 Isolate 中完成:
Student parseStudent(String content) => Student.fromJson(json.decode(content));
loadStudent() {
// 用 compute 函数将 json 解析放到新 Isolate
compute(parseStudent, jsonString).then((student) => flog("${student.name} - ${student.teacher.name}"));
}
2023-3-8
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/17190420.html