Flutter中的复杂Json编码/解码

时间:2018-10-08 21:07:26

标签: arrays json dart flutter

我将使用真实的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“:”设备已开启“ ,“ status_title”:“ on”}},{“ device_desc”:“ panke”,“ device_title”:“ panke”,“ functions”:[{“ device_id”:2,“ function_desc”:“ less”,“ function_title “:” pomp“,”状态“:2},{” device_id“:2,” function_desc“:”少“,” function_title“:”少“,”状态“:2}],” image_path“:” vfx “,” status_id“:2,” statuss“:{” status_desc“:”设备已关闭“,” status_title“:”关闭“}}}}

为了更好地理解,我在下面提供了屏幕截图

for more details

,这是解析json的站点的链接: http://json.parser.online.fr/

最后,这是我的代码:

这些是用于定义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),
                    )*/
                    );
                  }
                  );

                },
              );
            }
          },
        ),
      ),
    );
  }
}

调试时出现错误,即  “类型“列表”不是类型“列表”的子类型”

因此,我无法从json获取数据 tnx寻求帮助:)

3 个答案:

答案 0 :(得分:2)

关于如何在Flutter中解析复杂的JSON有一个很好的article。快速摘要...

简单的东西:

{
  "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'])
  );

答案 1 :(得分:2)

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

  

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

对于复杂的JSON,您可能需要考虑使用代码生成来减少必须编写的样板。扑动页面使用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. 您没有字段状态的状态列表,只有一个Status对象。
    2. 不要使用私有字段。
  2. 要启用json样板代码生成,请执行以下三个步骤:

    1. 将json注释添加到每个类
    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

答案 2 :(得分:0)

  
    

调试时出现错误,即“列表类型不是列表类型的子类型”

  

此示例应该可以正常工作。

import 'dart:convert';

import 'json_objects.dart';

void main() {
  var jsonObject = jsonDecode(_data) as Map<String, dynamic>;
  var response = Response1.fromJson(jsonObject);
  for (var device in response.devices) {
    print(device.deviceTitle);
    for (var function in device.functions) {
      print('  ' + function.functionTitle);
    }
  }
}

var _data = '''
{"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"}}]}
''';

结果:

cooler
  pomp
  less
  up
panke
  pomp
  less

大多数问题是由数据模型的缺陷引起的。在此示例中,使用了以下数据模型。

class Devices {
  final String deviceDesc;
  final String deviceTitle;
  final List<Functions> functions;
  final String imagePath;
  final int statusId;
  final Statuss statuss;

  Devices(
      {this.deviceDesc,
      this.deviceTitle,
      this.functions,
      this.imagePath,
      this.statusId,
      this.statuss});

  factory Devices.fromJson(Map<String, dynamic> json) {
    return Devices(
      deviceDesc: json['device_desc'] as String,
      deviceTitle: json['device_title'] as String,
      functions: _toObjectList(json['functions'], (e) => Functions.fromJson(e)),
      imagePath: json['image_path'] as String,
      statusId: json['status_id'] as int,
      statuss: _toObject(json['statuss'], (e) => Statuss.fromJson(e)),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'device_desc': deviceDesc,
      'device_title': deviceTitle,
      'functions': _fromList(functions, (e) => e.toJson()),
      'image_path': imagePath,
      'status_id': statusId,
      'statuss': statuss?.toJson(),
    };
  }
}

class Functions {
  final int deviceId;
  final String functionDesc;
  final String functionTitle;
  final int status;

  Functions(
      {this.deviceId, this.functionDesc, this.functionTitle, this.status});

  factory Functions.fromJson(Map<String, dynamic> json) {
    return Functions(
      deviceId: json['device_id'] as int,
      functionDesc: json['function_desc'] as String,
      functionTitle: json['function_title'] as String,
      status: json['status'] as int,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'device_id': deviceId,
      'function_desc': functionDesc,
      'function_title': functionTitle,
      'status': status,
    };
  }
}

class Response1 {
  final List<Devices> devices;

  Response1({this.devices});

  factory Response1.fromJson(Map<String, dynamic> json) {
    return Response1(
      devices: _toObjectList(json['devices'], (e) => Devices.fromJson(e)),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'devices': _fromList(devices, (e) => e.toJson()),
    };
  }
}

class Statuss {
  final String statusDesc;
  final String statusTitle;

  Statuss({this.statusDesc, this.statusTitle});

  factory Statuss.fromJson(Map<String, dynamic> json) {
    return Statuss(
      statusDesc: json['status_desc'] as String,
      statusTitle: json['status_title'] as String,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'status_desc': statusDesc,
      'status_title': statusTitle,
    };
  }
}

List _fromList(data, Function(dynamic) toJson) {
  if (data == null) {
    return null;
  }
  var result = [];
  for (var element in data) {
    var value;
    if (element != null) {
      value = toJson(element);
    }
    result.add(value);
  }
  return result;
}

T _toObject<T>(data, T Function(Map<String, dynamic>) fromJson) {
  if (data == null) {
    return null;
  }
  return fromJson(data as Map<String, dynamic>);
}

List<T> _toObjectList<T>(data, T Function(Map<String, dynamic>) fromJson) {
  if (data == null) {
    return null;
  }
  var result = <T>[];
  for (var element in data) {
    T value;
    if (element != null) {
      value = fromJson(element as Map<String, dynamic>);
    }
    result.add(value);
  }
  return result;
}

/*
Response1:
  "devices": List<Devices>

Devices:
  "device_desc": String
  "device_title": String
  "functions": List<Functions>
  "image_path": String
  "status_id": int
  "statuss": Statuss

Functions:
  "device_id": int
  "function_desc": String
  "function_title": String
  "status": int

Statuss:
  "status_desc": String
  "status_title": String
*/