和谐学习!不急不躁!!我是你们的老朋友小青龙~
-
Flutter
常用的网络库,以http
和dio
库为多,本文以http
为例。 -
json转模型的两种方法:
-
json_annotation
-
如果想了解dio
的使用,请前往
1、如何集合第三方库http
?
- 打开第三方开源库,搜索
http
点击它会复制库名+版本号
来到我们的工程目录,找到并打开pubspec.yaml
2、如何使用第三方库http
呢?
在你需要使用网络的地方导入
import 'package:http/http.dart' as http;
然后在initState
里
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
// 此处省略无关代码
...
}
@override
void initState() {
super.initState();
//发送一个get请求
sendHttp();
}
void sendHttp() async {
var url = Uri.parse('http://rap2api.taobao.org/app/mock/293606/api/chat/list');
var response = await http.get(url);
print('打印看看 reasonPhrase ->${response.reasonPhrase}');
print('打印看看 request-> ${response.request}');
print('打印看看 statusCode-> ${response.statusCode}');
print('打印看看 contentLength-> ${response.contentLength}');
print('打印看看 headers-> ${response.headers}');
print('打印看看 isRedirect-> ${response.isRedirect}');
print('打印看看 persistentConnection-> ${response.persistentConnection}');
print('打印看看 body->${response.body}');
}
}
打印结果:
3、Json字符串转数据模型(json_annotation
)
前面,我们顺利的拿到了网络请求返回的Json字符串数据,那么如何转化成我们定义好的模型类呢?
3.1、配置pubspec.yaml
这里我们需要用到几个库
-
json_annotation
-
build_runner
-
json_serializable
打开pubspec.yaml
,开始配置、加载第三方库
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
http: ^0.13.4
json_annotation: ^4.3.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
json_serializable: ^6.0.1
build_runner: ^1.8.0
3.2、配置数据模型
创建一个student.dart
文件,并按照下图模版
填好,以后其他模型数据也可以这么来写
import 'package:json_annotation/json_annotation.dart';
part 'student.g.dart';
@JsonSerializable()
class StudentRoot {
String code;
List<Student> list;
StudentRoot({required this.code, required this.list});
factory StudentRoot.fromJson(Map<String, dynamic> json) =>
_$StudentRootFromJson(json);
Map<String, dynamic> toJson() => _$StudentRootToJson(this);
}
@JsonSerializable()
class Student {
String studentName;
int studentAge;
int studentId;
Student(
{required this.studentName,
required this.studentAge,
required this.studentId});
factory Student.fromJson(Map<String, dynamic> json) =>
_$StudentFromJson(json);
// Map<String, dynamic> toJson(Student instance) => _$StudentToJson(instance);
Map<String, dynamic> toJson() => _$StudentToJson(this);
}
我们发现part 'student.g.dart';
这行报错了,先不用管后面会生成的
。
3.3、准备测试接口
http://rap2api.taobao.org/app/mock/293606/api/flutter/jsonmodel
3.4、窗口执行命令
打开Android studio 左下角
自带Terminal
窗口
输入以下命令
并按下回车
flutter pub run build_runner build
执行完是这样的
当然有的小伙伴可能发现执行完:
-
part 'student.g.dart';
这行依旧报错 -
student.g.dart
这个文件也没有生成
小编也遇到过这个问题,不妨试试以下几个方法:
-
关闭那几个文件创建,
重新运行
项目 -
重启Android studio
3.5、使用
前面的几步都是铺垫,接下来才是我们的重头戏。
使用方法
void sendHttp() async {
var url = Uri.parse(
'http://rap2api.taobao.org/app/mock/293606/api/flutter/jsonmodel');
var response = await http.get(url);
print('JsonPage打印看看 body->${response.body}');
// Json转StudentRoot
Map mapJson = jsonDecode(response.body);
String data = utf8.decode(response.bodyBytes);
StudentRoot studentRoot = StudentRoot.fromJson(json.decode(data));
// StudentRoot转Json
String jsonAfter = jsonEncode(studentRoot);
// 下面是测试代码~~
print('查看请求状态码 ---${studentRoot.code}');
print('查看list ---${studentRoot.list}');
for (var listChild in studentRoot.list) {
print('查看list子元素 ---${listChild.studentName}');
}
print('StudentRoot转Json打印 $jsonAfter');
}
运行结果:
如何使用在线工具quicktype
上面截图忘记标注了,类名可以在左上角
StuRoot处
改动
复制代码,新建模型文件stu.dart
,粘贴即可
来到我们的json_page.dart
测试文件,
导入头文件
import 'package:ssj_wechat_demo/models/stu.dart';
使用方法也很简单~
// StudentRoot studentRoot = StudentRoot.fromJson(json.decode(data));
// 注释上面这行,改用下面这行,其它不动
StuRoot studentRoot = stuRootFromJson(response.body);
Future的使用
有时候,我们希望在异步任务结束之后再主动做一些事情
,这个时候可以考虑用官网提供的Future
。
Future
带有一个then
属性,then是一个带有value参数的方法,即在返回Future之后会主动调用then里的方法。
具体使用如下:
void initState() {
super.initState();
print('JsonPage - 开始请求');
sendHttp().then((value) {
print('then代码块开始执行->$value');
});
print('JsonPage - 请求执行完毕');
}
Future<List<ListElement>> sendHttp() async {
var url = Uri.parse(
'http://rap2api.taobao.org/app/mock/293606/api/flutter/jsonmodel');
var response = await http.get(url);
if (response.statusCode == 200) {
// Json转StudentRoot
Map mapJson = jsonDecode(response.body);
String data = utf8.decode(response.bodyBytes);
// StudentRoot studentRoot = StudentRoot.fromJson(json.decode(data));
// 注释上面这行,改用下面这行,其它不动
StuRoot studentRoot = stuRootFromJson(response.body);
// StudentRoot转Json
String jsonAfter = jsonEncode(studentRoot);
return studentRoot.list;
} else {
print('请求失败');
throw Exception('请求失败,code:${response.statusCode}');
}
}
运行效果:
从打印结果看,then
代码块确实是最后执行
的,value
参数则是Future包含的返回值
。
FutureBuilder
方法都可以通过返回Future来实现异步执行任务,那么我们的widget组件是否也有类似的东西呢,还真别说,官网为我们提供了这么一个组件:FutureBuilder
。
FutureBuilder有两个属性
- future
- builder
首先,我们来看下怎么用:
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: sendHttp(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('snapshot:$snapshot');
return Container(
child: const Text('我加载完了~'),
);
}),
);
}
运行效果:
我们发现,builder方法被执行了两次,分别是Future返回前后各执行一次。利用这个特性,我们可以对一些耗时请求,添加友好提示,比如“加载ing~”等字眼。
说干就干:
// sendHttp()跟前面一样
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: sendHttp(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('snapshot:$snapshot');
if (snapshot.data == null) {
return Container(
color: Colors.red,
child: const Center(
child: Text(
'加载ing~',
textAlign: TextAlign.center,
),
),
);
} else {
// else代码块可以根据实际需求进行修改
return Container(
color: Colors.yellow,
child: const Center(
child: Text(
'我加载完了~',
textAlign: TextAlign.center,
),
),
);
}
}),
);
}
效果图:
另外, FutureBuilder最适用的是数据一次就获取,不需要频繁获取数据,改变页面内容的情况下,因为future的方法不能够重新执行,所以要刷新页面可能需要刷新整个widget。