在 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
Flutter Gzip 编码与解码 Dart Gzip 工具类操作