【问题标题】:Encoding / decoding complex Json in Flutter在 Flutter 中编码/解码复杂的 Json
【发布时间】: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 中获取数据。

【问题讨论】:

    标签: arrays json dart flutter


    【解决方案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 的好例子。以下是您示例的基本说明:

      1. 将依赖项添加到pubspec.yaml 并在命令行中运行flutter pub get
          dependencies:        
              json_annotation: ^1.2.0
      
          dev_dependencies:       
              build_runner: ^1.0.0 
              json_serializable: ^1.5.1
      
      1. 创建基本的对象模型(类似于您所做的)。除了以下区别:

        1. 您没有字段状态的状态列表,而是一个状态对象。
        2. 不要使用私有字段。
      2. 要启用 json 样板代码生成,请执行以下三个步骤:

        1. 为每个类添加 json-annotations,
        2. 在每个类上添加工厂 .fromJson 方法并
        3. 在每个类上添加一个 .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);       
          }
      
      1. 在项目根文件夹中运行命令行开始代码生成:
          flutter packages pub run build_runner watch
      
      1. 现在会出现一个附加源文件,其中包含您生成的样板代码。使用 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'])
        );
      

      【讨论】:

      • 非常感谢;) 文章中准确地提到了我的错误,所以我可以解决我的问题
      猜你喜欢
      • 2021-12-28
      • 2020-05-10
      • 2010-11-16
      • 2019-05-26
      • 2020-12-21
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多