在 Flutter 中编码/解码复杂的 Json

Posted

技术标签:

【中文标题】在 Flutter 中编码/解码复杂的 Json【英文标题】:Encoding / decoding complex Json in Flutter 【发布时间】:2019-03-13 14:07:30 【问题描述】:

我将使用真正的 json。首先,我应该运行用Flask编写的项目,然后使用本地主机来实现数据。 这是我正在使用的真正的 Json


   "devices":[
      
         "device_desc":"cooler",
         "device_title":"cooler",
         "functions":[
            
               "device_id":1,
               "function_desc":"pomp",
               "function_title":"pomp",
               "status":1
            ,
            
               "device_id":1,
               "function_desc":"less",
               "function_title":"less",
               "status":1
            ,
            
               "device_id":1,
               "function_desc":"up",
               "function_title":"up",
               "status":1
            
         ],
         "image_path":"fdfdfsf",
         "status_id":1,
         "statuss":
            "status_desc":"device is on",
            "status_title":"on"
         
      ,
      
         "device_desc":"panke",
         "device_title":"panke",
         "functions":[
            
               "device_id":2,
               "function_desc":"less",
               "function_title":"pomp",
               "status":2
            ,
            
               "device_id":2,
               "function_desc":"less",
               "function_title":"less",
               "status":2
            
         ],
         "image_path":"vfx",
         "status_id":2,
         "statuss":
            "status_desc":"device is off",
            "status_title":"off"
         
      
   ]

这是我的代码:

这些是用于定义 json 属性的数据模型:

class Base
//the type of our object is the array
  List<Device> _devices;


  Base(this._devices);

  List<Device> get devices => _devices;

  set devices(List<Device> value) 
    _devices = value;
  


class Device 
  String _device_desc,_device_title,_image_path;
  int _status_id;
  List<function> _functions;
  List<Status> _statuss ;

  Device(this._device_desc, this._device_title, this._image_path,
      this._status_id, this._functions, this._statuss);

  List<Status> get statuss => _statuss;

  set statuss(List<Status> value) 
    _statuss = value;
  

  List<function> get functions => _functions;

  set functions(List<function> value) 
    _functions = value;
  

  int get status_id => _status_id;

  set status_id(int value) 
    _status_id = value;
  

  get image_path => _image_path;

  set image_path(value) 
    _image_path = value;
  

  get device_title => _device_title;

  set device_title(value) 
    _device_title = value;
  

  String get device_desc => _device_desc;

  set device_desc(String value) 
    _device_desc = value;
  


class Status 
  String _status_desc, _status_title;

  Status(this._status_desc, this._status_title);

  get status_title => _status_title;

  set status_title(value) 
    _status_title = value;
  

  String get status_desc => _status_desc;

  set status_desc(String value) 
    _status_desc = value;
  
class function 
   String _function_desc, _function_title;
   int _device_id, _status;

   function(this._function_desc, this._function_title, this._device_id,
       this._status);

   get status => _status;

   set status(value) 
     _status = value;
   

   int get device_id => _device_id;

   set device_id(int value) 
     _device_id = value;
   

   get function_title => _function_title;

   set function_title(value) 
     _function_title = value;
   

   String get function_desc => _function_desc;

   set function_desc(String value) 
     _function_desc = value;
   

这是有状态的类:

class MyHomePage extends StatefulWidget 
  var title;

  MyHomePage(Key key, this.title) : super(key: key);

  @override
  _MyHomePageState createState() => new _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 


  Future<Base> _getBase() async 
var data = await http.get(Uri.encodeFull("http://192.168.1.111:5000/mobile-home"));
var jsonData = json.decode(data.body);

Base base = Base(jsonData);
  return Base(jsonData[0]);
  

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder(
          future: _getBase(),
          builder: (BuildContext context,  AsyncSnapshot snapshot) 
            if (snapshot.data == null) 
              return Container(
                child: Center(
                  child: Text("Loading..."),
                ),
              );
             else 
              return ListView.builder(
                itemCount: snapshot.data.devices.length,
                itemBuilder: (BuildContext context, int index) 
                  snapshot.data.devices.map<Widget>((devices)
                    return ListTile(
                      subtitle: Text(devices[index].device_desc.toString()),
                      title: Text(devices[index].device_title),
                      /*leading: CircleAvatar(
                      // ignore: argument_type_not_assignable
                      backgroundImage:  NetworkImage(snapshot.data[index].thumbnailUrl),
                    )*/
                    );
                  
                  );

                ,
              );
            
          ,
        ),
      ),
    );
  

调试时出错:

 "type 'List<dynamic>' is not a subtype of type 'List<Device>'"

我无法从 json 中获取数据。

【问题讨论】:

【参考方案1】:

使用 jsonDecode() 将 JSON 编码的字符串解码为 Dart 对象:

// NOTE: Be sure to use double quotes ("),
// not single quotes ('), inside the JSON string.
// This string is JSON, not Dart.
var jsonString = '''
  [
    "score": 40,
    "score": 80
  ]
''';

var scores = jsonDecode(jsonString);
assert(scores is List);

var firstScore = scores[0];
assert(firstScore is Map);
assert(firstScore['score'] == 40);

使用jsonEncode() 将支持的 Dart 对象编码为 JSON 格式的字符串:

var scores = [
  'score': 40,
  'score': 80,
  'score': 100, 'overtime': true, 'special_guest': null
];

var jsonText = jsonEncode(scores);
assert(jsonText ==
    '["score":40,"score":80,'
        '"score":100,"overtime":true,'
        '"special_guest":null]');

只有 int、double、String、bool、null、List 或 Map(带有字符串键)类型的对象可以直接编码为 JSON。 List 和 Map 对象是递归编码的。

对于不可直接编码的对象,您有两种选择。第一种是使用第二个参数调用jsonEncode():一个返回可直接编码的对象的函数。第二个选项是省略第二个参数,在这种情况下编码器调用对象的toJson() 方法。

【讨论】:

【参考方案2】:

你的问题没有问题,但我认为问题是:

我的 Json 代码不起作用 - 我如何有效地解析和编码我的复杂 json 对象 颤振程序。

对于复杂的 JSON,您可能需要考虑使用代码生成来减少您必须编写的样板代码。 Flutter 页面有一个使用 JsonSerializable 的好例子。以下是您示例的基本说明:

    将依赖项添加到pubspec.yaml 并在命令行中运行flutter pub get
    dependencies:        
        json_annotation: ^1.2.0

    dev_dependencies:       
        build_runner: ^1.0.0 
        json_serializable: ^1.5.1

    创建基本的对象模型(类似于您所做的)。除了以下区别:

      您没有字段状态的状态列表,而是一个状态对象。 不要使用私有字段。

    要启用 json 样板代码生成,请执行以下三个步骤:

      为每个类添加 json-annotations, 在每个类上添加工厂 .fromJson 方法并 在每个类上添加一个 .toJson 方法:
    @JsonSerializable()
    class Base 
      List<Device> devices;
      Base(this.devices);
      factory Base.fromJson(Map<String, dynamic> json) => _$BaseFromJson(json);     
      Map<String, dynamic> toJson() => _$BaseToJson(this); 
    

    @JsonSerializable()
    class Device 
      String device_desc,device_title,image_path;
      int status_id;
      List<function> functions;
      Status statuss ;
      Device(this.device_desc, this.device_title, this.image_path,
          this.status_id, this.functions, this.statuss);
      factory Device.fromJson(Map<String, dynamic> json) => _$DeviceFromJson(json);       
      Map<String, dynamic> toJson() => _$DeviceToJson(this); 
    

    @JsonSerializable()
    class Status 
      String status_desc, status_title;
      Status(this.status_desc, this.status_title);
      factory Status.fromJson(Map<String, dynamic> json) => _$StatusFromJson(json);   
      Map<String, dynamic> toJson() => _$StatusToJson(this); 
    

    @JsonSerializable()
    class function 
      String function_desc, function_title;
      int device_id, status;
      function(this.function_desc, this.function_title, this.device_id,
          this.status);
      factory function.fromJson(Map<String, dynamic> json) => _$functionFromJson(json);  
      Map<String, dynamic> toJson() => _$functionToJson(this);       
    
    在项目根文件夹中运行命令行开始代码生成:
    flutter packages pub run build_runner watch
    现在会出现一个附加源文件,其中包含您生成的样板代码。使用 part 关键字将此文件添加到您自己的源文件中,例如,如果您的源文件是 main.dart,请添加以下行:
    part 'main.g.dart';

您就完成了 - 这就是您测试编码/解码所需的全部内容。比如下面的代码:

    import 'dart:convert';
    void main() => ()
      var jsonExample = '"devices": ["device_desc": "cooler", "device_title": "cooler", "functions": ["device_id": 1, "function_desc": "pomp", "function_title": "pomp", "status": 1, "device_id": 1, "function_desc": "less", "function_title": "less", "status": 1, "device_id": 1, "function_desc": "up", "function_title": "up", "status": 1], "image_path": "fdfdfsf", "status_id": 1, "statuss": "status_desc": "device is on", "status_title": "on", "device_desc": "panke", "device_title": "panke", "functions": ["device_id": 2, "function_desc": "less", "function_title": "pomp", "status": 2, "device_id": 2, "function_desc": "less", "function_title": "less", "status": 2], "image_path": "vfx", "status_id": 2, "statuss": "status_desc": "device is off", "status_title": "off"]';

      Map base_example = json.decode(jsonExample);
      Base base_example_parsed = Base.fromJson(base_example);
      var numberDevices = base_example_parsed.devices.length;
      var numberFuncs = base_example_parsed.devices[0].functions.length;
      print('$base_example_parsed has $numberDevices devices and the first device has $numberFuncs functions');

      var base_example_encoded_again = json.encode(base_example_parsed);
      print('$base_example_encoded_again');
    ;

更多信息请参考: 1.official example。 2.这个blog.

【讨论】:

我添加了它显示的错误,“type 'List' is not a subtype of type 'List'” 其实我是一个初学者,我想自己写代码只是为了练习,但老实说你的答案很棒,因为它很清楚并且尽可能简单!tnx 为您提供很好的答案,我肯定会使用此方法【参考方案3】:

有一个很好的article 关于如何在 Flutter 中解析复杂的 JSON。这是一个简短的总结...

简单的东西:


  "id":"487349",
  "name":"Pooja Bhaumik",
  "score" : 1000

变成……

class Student
  String studentId;
  String studentName;
  int studentScores;

  Student(
    this.studentId,
    this.studentName,
    this.studentScores
 );

  factory Student.fromJson(Map<String, dynamic> parsedJson)
    return Student(
      studentId: parsedJson['id'],
      studentName : parsedJson['name'],
      studentScores : parsedJson ['score']
    );
  


您创建一个新的 Student 对象,例如 Student.fromJson(your_parsed_json)

子对象以类似的方式工作。对于父对象中的每个对象,您创建一个新的 Dart 对象,每个对象都有自己的 fromJson 解析器。然后在父工厂中调用 fromJson 方法(就像这样)......这也适用于对象列表。

  factory Student.fromJson(Map<String, dynamic> parsedJson)
    return Student(
      studentId: parsedJson['id'],
      studentName : parsedJson['name'],
      studentScores : Teacher.fromJson(parsedJson['teacher'])
  );

【讨论】:

非常感谢;) 文章中准确地提到了我的错误,所以我可以解决我的问题

以上是关于在 Flutter 中编码/解码复杂的 Json的主要内容,如果未能解决你的问题,请参考以下文章

本文将向您展示如何在 Flutter 中编码/解码 JSON

如何在 dart/flutter 中解码复杂的 json?

Flutter Gzip 编码与解码 Dart Gzip 工具类操作

解码复杂的 JSON?

将 Tensorflow Keras 模型(编码器 - 解码器)保存为 SavedModel 格式

谷歌编码问题 base64 和 PHP 解码