注册

flutter 项目中json转dart模型

前言


实际开发项目中,后端返回的数据大多数是json格式,例如上一篇 Flutter 自定义数据选择器 中显示的数据都是dart模型的数据,由于dart本身数据格式并没有json格式,所以需要转化成dart模型数据。


解决方案


1. 小项目手动序列化


dart:convert 中内置的JSON解码器 它将原始JSON字符串传递给JSON.decode() 方法,然后在返回的Map<String, dynamic>中查找所需的值。 它没有外部依赖或其它的设置,对于小项目很方便


2.对于大中型项目 使用 json to Dart 网站生成model类


3. 使用插件 json_serializable package


实际应用


以方案1 和方案2 在实际项目中展示,还是以上一篇的[Flutter 自定义数据选择器] 为例


由于json to Dart 这个转换已经支持空安全,所以如果需要改动


pubspec.yaml文件


environment:
sdk: ">=2.12.0 <3.0.0" #如果需要支持空安全,只需要这里改一下版本 >=2.7.0 改成2.12.0

执行:


flutter clean

flutter pub get

area-data-jsonString.dart 文件


定义一个json 字符串数据(由于dart 没有json数据类型, 本地模拟数据就用json数据组装成 字符串格式,'''XXX ''' 包裹起来, 注意是 三个单引号)


image.png


进入 json to Dart
粘贴 ,定义类型


image.png


转化的模型数据如下:


area-data-json.dart


class AreaDataToJson {
String? id;
String? name;
String? center;
int? level;
List<Children>? children;

AreaDataToJson({this.id, this.name, this.center, this.level, this.children});

AreaDataToJson.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
center = json['center'];
level = json['level'];
if (json['children'] != null) {
children = <Children>[];
json['children'].forEach((v) {
children!.add(new Children.fromJson(v));
});
}
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['center'] = this.center;
data['level'] = this.level;
if (this.children != null) {
data['children'] = this.children!.map((v) => v.toJson()).toList();
}
return data;
}
}

class Children {
String? id;
String? name;
String? center;
int? level;

Children({this.id, this.name, this.center, this.level});

Children.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
center = json['center'];
level = json['level'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['center'] = this.center;
data['level'] = this.level;
return data;
}
}

仔细对比发现这里生成数据有问题,省市区是有三层数据,这里只有两层(chilren下面下面可能还存在一层,这里后面再研究一下)


custom-pick.dart 这里就不贴出来,跟上一篇[Flutter 自定义数据选择器] 一样,去上面查看或者查看github源码


如下调用:
json-picker-page.dart



import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:personal_app/components/custom-picker.dart';
import 'package:personal_app/data/area-data-jsonString.dart';
import 'package:personal_app/Modal/area-data-json.dart';

class JsonPickerPage extends StatefulWidget {

@override
_JsonPickerPageState createState() => _JsonPickerPageState();
}

class _JsonPickerPageState extends State<JsonPickerPage> {
// 方案一
List<dynamic> provAreaDataIdxs = [];//省市区的选择数据下标集合
String provAreaName = '';// 省市区名称
dynamic provAreaValue; //省市区选的数据id
List<Map<String, dynamic>> resetAreaData = []; //省市区数据转换后的数据

// 方案二
List<dynamic> provAreaDataIdxs2 = [];//省市区的选择数据下标集合
String provAreaName2 = '';// 省市区名称
dynamic provAreaValue2; //省市区选的数据id
List<Map<String, dynamic>> resetAreaData2 = []; //省市区数据转换后的数据


@override
void initState() {
//方式1,因为数据是本地的数据,dart本身是没有dart数据格式,
// 所以在定义json数据格式时,需要加上'''XXX''' 先包裹成字符串
//所以需要解析成List ,真实的接口请求不需要这么处理
List<dynamic> AreaDataJson = json.decode(areaDataJsonSting);//Json 改成小写,升级原因
//需要注意的是 areaData 数据字段不是label 和value; 需要转化一下
resetAreaData =recursionDataHandle(AreaDataJson);

//方式 2
List<dynamic> AreaDataJson2 = json.decode(areaDataJsonSting);
List<dynamic> AreaDataDart2 = AreaDataJson2.map((item) =>
new AreaDataToJson.fromJson(item)).toList();
print(AreaDataDart2.toString()); //这里打印才发现AreaDataToJson类有问题,该网站不能对于这种树形结构的数据生成还存在问题,下面放开2层 即 省市是没问题的

// // List<Map<String, dynamic>> AreaDataDart = AreaDataToJson.fromJson(AreaDataJson);
//需要注意的是 areaData 数据字段不是label 和value; 需要转化一下
resetAreaData2 =recursionDataHandle(AreaDataDart2);
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("自定义数据选择器"),
),
body: Center(
child: GestureDetector(
onTap: (){
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
RaisedButton(
padding: EdgeInsets.all(0),
onPressed: () {
customPicker(context,
{"indexs":provAreaDataIdxs, "initData": resetAreaData, "colNum":3},
(opt) {
setState(() {
provAreaDataIdxs = opt['indexs'];
List names = opt['names'];
provAreaName = '';
for(int i = 0; i< names.length; i++) {
provAreaName += names[i]['label'] != '' ? i== 0 ? names[i]['label'] : '/' + names[i]['label'] : '';
}
provAreaValue = names[names.length-1]['value'];//value 这里逻辑只需要取最后一个
});
});
},
child: Row(
children: [
Text('省市区选择方案1'),

],
),
),
Text(provAreaName),
Container(
height: 26.0,
),
RaisedButton(
padding: EdgeInsets.all(0),
onPressed: () {
customPicker(context,
{"indexs":provAreaDataIdxs2, "initData": resetAreaData2, "colNum":2},
(opt) {
setState(() {
provAreaDataIdxs2 = opt['indexs'];
List names = opt['names'];
provAreaName2 = '';
for(int i = 0; i< names.length; i++) {
provAreaName2 += names[i]['label'] != '' ? i== 0 ? names[i]['label'] : '/' + names[i]['label'] : '';
}
provAreaValue2 = names[names.length-1]['value'];//value 这里逻辑只需要取最后一个
});
});
},
child: Row(
children: [
Text('省市区选择方案2'),
],
),
),
Text(provAreaName2),
Container(
height: 26.0,
),
]
),
),
),
);
}

//数据格式转换
recursionDataHandle(data) {
List<Map<String, dynamic>> resetData = [];
if(data?.length > 0) {
for (var i = 0; i <data?.length; i++) {
Map<String, dynamic> tmpData;
try {
tmpData = data?[i].toJson();
} catch(e) {
tmpData = data?[i];
}

resetData.add({
'value': tmpData['id'],
'label': tmpData['name'],
'center': tmpData['center'],
'level': tmpData['level'],
// 'children': data[i]['children'] ? recursionDataHandle(data[i]['children']): []
});
if(tmpData.containsKey('children')) { //是否包含key值children
if(tmpData['children']?.length > 0) {
resetData[i]['children'] = recursionDataHandle(tmpData['children']);
} else {
resetData[i]['children'] = [];
}
}
}
}
return resetData;
}
}

方式1 和方式2 分别对应着上面的方案1 和方案2


效果:


image.png


问题


需要研究一下 json to Dart 类似多层树形结构数据存在问题?


作者:杰森陈
链接:https://juejin.cn/post/7071939995233157134
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册