likes
comments
collection
share

flutter 项目中json转dart模型

作者站长头像
站长
· 阅读数 56

前言

实际开发项目中,后端返回的数据大多数是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 ''' 包裹起来, 注意是 三个单引号)

flutter 项目中json转dart模型

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

flutter 项目中json转dart模型

转化的模型数据如下:

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

效果:

flutter 项目中json转dart模型

问题

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

结语

项目源码 github.com/chenbing11/… master分支 有需要请自取

创作不易,请多点赞+关注,谢谢! 有问题留言,我都会及时回复