Google推出flutter这样一个新的高性能跨平台(Android,ios)快速开发框架以后,被业界许多开发者所关注。我在接触了flutter以后发现这个确实是一个好东西,好东西固然要和你们分享,对吧。html
今天要跟你们分享的是Json反序列化的实现。相信作app的同窗都会遇到这么一个问题,在向服务器请求数据后,服务器每每会返回一段json字符串。而咱们要想更加灵活的使用数据的话须要把json字符串转化成对象。因为flutter只提供了json to Map。而手写反序列化在大型项目中极不稳定,很容易致使解析失败。因此今天给你们介绍的是flutter团队推荐使用的 json_serializable 自动反序列化。ios
在实际开发过程当中,咱们可能会对以前的一些代码进行修改。当咱们代码功能复杂而且量足够大的时候,咱们须要使用单元测试来保证新添加的代码不会影响以前所写的代码。而服务器的数据常常会变化,因此第一步固然是建立一个咱们的mock数据啦。git
这里使用了GITHUB/HackerNews的数据(github.com/HackerNews/…)github
abstract class JsonString{
static final String mockdata = ''' { "by" : "dhouston", "descendants" : 71, "id" : 8863, "kids" : [ 8952, 9224, 8917, 8884, 8887, 8943, 8869, 8958, 9005, 9671, 8940, 9067, 8908, 9055, 8865, 8881, 8872, 8873, 8955, 10403, 8903, 8928, 9125, 8998, 8901, 8902, 8907, 8894, 8878, 8870, 8980, 8934, 8876 ], "score" : 111, "time" : 1175714200, "title" : "My YC app: Dropbox - Throw away your USB drive", "type" : "story", "url" : "http://www.getdropbox.com/u/2/screencast.html" }''';
}
复制代码
在pubspec.yaml中添加以下依赖json
dependencies:
# Your other regular dependencies here
json_annotation: ^1.2.0
dev_dependencies:
# Your other dev_dependencies here
build_runner: ^0.10.2
json_serializable: ^1.5.1
复制代码
这里须要添加三个依赖,它们分别是:"json_annotation" "build_runner" 和 "json_serializable"。服务器
请注意,yaml配置文件对于缩进要求十分严格,下面的build_runner和json_serializable应该是与flutter_test平级的,千万不要写在flutter_test缩进后,这样它会认为这两个是flutter_test的子集目录!app
因为不少朋友在这一步遇到了问题,这里贴出源码框架
咱们这里根据上面的json数据写好了一个dart的实体类ide
class Data{
final String by;
final int descendants;
final int id;
final List<int> kids;
final int score;
final int time;
final String title;
final String type;
final String url;
Data({this.by, this.descendants, this.id, this.kids, this.score, this.time,
this.title, this.type, this.url});
}
复制代码
咱们在这里使用了dart语法糖建立了构造函数。具体请参考(www.dartlang.org/guides/lang…)。函数
咱们须要在咱们的实体类中关联生成文件。
import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
@JsonSerializable()
class Data {
final String by;
final int descendants;
final int id;
final List<int> kids;
final int score;
final int time;
final String title;
final String type;
@JsonKey(nullable: false)
final String url;
Data({this.by, this.descendants, this.id, this.kids, this.score, this.time,
this.title, this.type, this.url});
复制代码
刚写完data.g.dart的会报错,这是正常的!由于咱们还没生成解析文件
当当当...!这里开始就是重头戏了!!
咱们要使用JsonSerializable生成代码的话必需要在须要生成代码的实体类前添加注解@JsonSerializable(),而要使用这个注解咱们必须引入json_annotation/json_annotation.dart这个包。
import 'package:json_annotation/json_annotation.dart';
@JsonSerializable()
class Data{
final String by;
final int descendants;
final int id;
final List<int> kids;
final int score;
final int time;
final String title;
final String type;
final String url;
Data({this.by, this.descendants, this.id, this.kids, this.score, this.time,
this.title, this.type, this.url});
}
复制代码
这里须要注意,flutter编码规范dart文件名统一小写,这样能够避免不少问题。ok这样实体类就建立完成啦。
那么问题来了,应该如何生成代码呢?
还记得咱们刚才添加的build_runner的依赖吗,这时候咱们就须要它来帮忙咯。
build_runner是dart团队提供的一个生成dart代码文件的外部包。
咱们在当前项目的目录下运行flutter packages pub run build_runner build
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Data _$DataFromJson(Map<String, dynamic> json) {
return Data(
by: json['by'] as String,
descendants: json['descendants'] as int,
id: json['id'] as int,
kids: (json['kids'] as List)?.map((e) => e as int)?.toList(),
score: json['score'] as int,
time: json['time'] as int,
title: json['title'] as String,
type: json['type'] as String,
url: json['url'] as String);
}
Map<String, dynamic> _$DataToJson(Data instance) => <String, dynamic>{
'by': instance.by,
'descendants': instance.descendants,
'id': instance.id,
'kids': instance.kids,
'score': instance.score,
'time': instance.time,
'title': instance.title,
'type': instance.type,
'url': instance.url
};
复制代码
同志们请注意这段代码最上面的注释"// GENERATED CODE - DO NOT MODIFY BY HAND"。你可千万别手写生成文件啊哈哈哈哈。
这段代码生成实体类库的一个part,在老版本part中有一个抽象实体类的mixin,dart中使用基于mixin的继承来解决单继承的局限性。
新版本中声称了两个方法,fromJson和toJson方法,它们能干什么相信你们从名字上就能猜到了。
【对part感兴趣的同窗能够参考https://juejin.im/post/5b601f40e51d4519575a5036#heading-8 Dart | 浅析dart中库的导入与拆分。
对mixin感兴趣的同窗能够在(www.dartlang.org/guides/lang…)了解更多关于mixin的知识。】
而这两个都是私有方法,part让两个文件共享做用域与命名空间,因此咱们须要将生成的方法暴露给外部。
而后咱们再回到实体类中将 添加fromJson 和 toJson方法。
import 'package:json_annotation/json_annotation.dart';
@JsonSerializable()
class Data{
final String by;
final int descendants;
final int id;
final List<int> kids;
final int score;
final int time;
final String title;
final String type;
final String url;
Data({this.by, this.descendants, this.id, this.kids, this.score, this.time,
this.title, this.type, this.url});
//反序列化
factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);
//序列化
Map<String, dynamic> toJson() => _$DataToJson(this);
}
复制代码
这样Json反序列化的工做就完成啦!
咱们刚才实现了Map to Dart,但是咱们须要的是json to dart。这时候就须要dart自带的 dart:convert 来帮助咱们了。
dart:convert是dart提供用于在不一样数据表示之间进行转换的编码器和解码器,可以解析JSON和UTF-8。
也就是说咱们须要先将json数据使用dart:convert转成Map,咱们就能经过Map转为dart对象了。
使用方法
Map<String ,dynamic> map = json.decode("jsondata");
复制代码
知道了如何将jsonString解析成map之后咱们就能直接将json转化为实体对象啦。
转化方法
Data data = Data.fromJson(json.decode('jsondata'));
复制代码
flutter给咱们提供了单元测试,它的好处在于,咱们想要验证代码的正确性不用跑整个程序,每次只用跑一个单元测试文件。并且养成习惯编写单元测试之后,可以保证之后在开发过程当中快速精肯定位错误,避免新加入的代码破坏老的代码引发项目崩溃。每次应用启动前都会跑一遍单元测试以确保项目可以正确运行。在实际开发中咱们应该使用的mock数据来做为测试数据来源。
使用方法: 右键run这个测试文件
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:wmkids/data/mockdata.dart';
import 'package:wmkids/data/data.dart';
void main(){
group('jsonparse test', (){
test('mockdata test', (){
Data data1 = Data.fromJson(json.decode(JsonString.mockdata));
expect(data1.url, 'http://www.getdropbox.com/u/2/screencast.html');
});
});
}
复制代码
咱们使用到了第一步建立的mock数据,并验证了该json的url,假如咱们解析正确这个单元测试将会经过。
这里的group是一组测试,一个group中能够有多个test验证咱们的代码是否正确。
expect(data1,data2);会check咱们的data1与data2的值是否相等,假如同样的话就会经过测试。假如不同的话会告诉咱们哪里不同。
在json中常常会使用嵌套信息,咱们在解析成dart文件的时候须要解析成对象嵌套。在这种场景下须要将编写步骤作一个调整。 咱们须要在编写实体类的时候就带上工厂方法,由于对象存在依赖关系,先要保证子对象是serializable的才能保证父对象成功解析。
咱们能够经过JsonKey自定义参数进行注释并自定义参数来自定义各个字段。例如:是否容许字段为空等。注意,这里不加任何JsonKey默认容许空json字段。
例如:
以上就是Flutter Json自动反序列化的所有内容,文章如有不对之处欢迎各位大牛指正!关于泛型问题如有更好的解决方案但愿能在评论区告诉我^-^。
以后我会更新一系列flutter干货喜欢的话能够关注我或者给我一个好评哦!我会更新更有动力的。