flutter-implement-json-serialization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSerializing JSON Manually in Flutter
在Flutter中手动序列化JSON
Contents
目录
Core Guidelines
核心准则
- Import : Utilize Flutter's built-in
dart:convertlibrary for manual JSON encoding (dart:convert) and decoding (jsonEncode).jsonDecode - Enforce Type Safety: Always cast the result of
dynamicto the expected type, typicallyjsonDecode()for objects orMap<String, dynamic>for arrays.List<dynamic> - Encapsulate Serialization Logic: Define plain model classes containing properties corresponding to the JSON structure. Implement a factory constructor and a
fromJsonmethod within the model.toJson - Handle Background Parsing: If parsing large JSON documents (execution time > 16ms), offload the parsing logic to a separate isolate using Flutter's function to prevent UI jank.
compute() - Throw Exceptions on Failure: When handling HTTP responses, throw an exception if the status code is not successful (e.g., not 200 OK or 201 Created). Do not return .
null
- 导入:利用Flutter内置的
dart:convert库进行手动JSON编码(dart:convert)和解码(jsonEncode)。jsonDecode - 强制类型安全:始终将返回的
jsonDecode()类型结果转换为预期类型,通常对象对应dynamic,数组对应Map<String, dynamic>。List<dynamic> - 封装序列化逻辑:定义与JSON结构对应的普通模型类,在模型内部实现工厂构造函数和
fromJson方法。toJson - 处理后台解析:如果解析大型JSON文档(执行时间>16ms),使用Flutter的函数将解析逻辑卸载到单独的isolate中,以避免UI卡顿。
compute() - 失败时抛出异常:处理HTTP响应时,如果状态码未表示成功(例如不是200 OK或201 Created),抛出异常,不要返回。
null
Workflow: Implementing a Serializable Model
工作流程:实现可序列化模型
Use this checklist to implement manual JSON serialization for a data model.
Task Progress:
- Define the plain model class with properties.
final - Implement the constructor.
factory Model.fromJson(Map<String, dynamic> json) - Implement the method.
Map<String, dynamic> toJson() - Write unit tests for both serialization methods.
- Run validator -> review type mismatch errors -> fix casting logic.
- Define the Model: Create a class with properties matching the JSON keys.
- Implement : Extract values from the
fromJsonand cast them to the appropriate Dart types. Use pattern matching or explicit casting.Map - Implement : Return a
toJsonmapping the class properties back to their JSON string keys.Map<String, dynamic> - Validate: Execute unit tests to ensure type safety, autocompletion, and compile-time exception handling function correctly.
使用此检查清单为数据模型实现手动JSON序列化。
任务进度:
- 定义带有属性的普通模型类。
final - 实现构造函数。
factory Model.fromJson(Map<String, dynamic> json) - 实现方法。
Map<String, dynamic> toJson() - 为两种序列化方法编写单元测试。
- 运行验证器 -> 检查类型不匹配错误 -> 修复类型转换逻辑。
- 定义模型:创建属性与JSON键匹配的类。
- 实现:从
fromJson中提取值并转换为合适的Dart类型,使用模式匹配或显式类型转换。Map - 实现:返回一个
toJson,将类属性映射回对应的JSON字符串键。Map<String, dynamic> - 验证:执行单元测试,确保类型安全、自动补全和编译时异常处理功能正常。
Workflow: Fetching and Parsing JSON
工作流程:获取并解析JSON
Use this conditional workflow when retrieving and parsing JSON from a network request.
Task Progress:
- Execute the HTTP request.
- Validate the response status code.
- Determine parsing strategy (Synchronous vs. Isolate).
- Decode and map the JSON to the model.
- Execute Request: Use the package to perform the network call.
http - Validate Response:
- If (or 201 for POST), proceed to parsing.
response.statusCode == 200 - If the status code indicates failure, throw an .
Exception
- If
- Determine Parsing Strategy:
- If parsing a small payload (e.g., a single object), parse synchronously on the main thread.
- If parsing a large payload (e.g., an array of thousands of objects), use to parse in a background isolate.
compute(parseFunction, response.body)
- Decode and Map: Pass the decoded JSON to your model's constructor.
fromJson
当从网络请求中获取并解析JSON时,使用此条件工作流程。
任务进度:
- 执行HTTP请求。
- 验证响应状态码。
- 确定解析策略(同步vs. Isolate)。
- 解码并将JSON映射到模型。
- 执行请求:使用包执行网络调用。
http - 验证响应:
- 如果(POST请求为201),继续解析。
response.statusCode == 200 - 如果状态码表示失败,抛出。
Exception
- 如果
- 确定解析策略:
- 如果解析小负载(例如单个对象),在主线程上同步解析。
- 如果解析大负载(例如数千个对象的数组),使用在后台isolate中解析。
compute(parseFunction, response.body)
- 解码并映射:将解码后的JSON传递给模型的构造函数。
fromJson
Examples
示例
High-Fidelity Model Implementation
高保真模型实现
dart
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory constructor for deserialization
factory User.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'id': int id,
'name': String name,
'email': String email,
} =>
User(
id: id,
name: name,
email: email,
),
_ => throw const FormatException('Failed to load User.'),
};
}
// Method for serialization
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}dart
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory constructor for deserialization
factory User.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'id': int id,
'name': String name,
'email': String email,
} =>
User(
id: id,
name: name,
email: email,
),
_ => throw const FormatException('Failed to load User.'),
};
}
// Method for serialization
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}Synchronous Parsing (Small Payload)
同步解析(小负载)
dart
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<User> fetchUser(http.Client client, int userId) async {
final response = await client.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Decode returns dynamic, cast to Map<String, dynamic>
final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}dart
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<User> fetchUser(http.Client client, int userId) async {
final response = await client.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Decode returns dynamic, cast to Map<String, dynamic>
final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}Background Parsing (Large Payload)
后台解析(大负载)
dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(
Uri.parse('https://api.example.com/users'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Offload expensive parsing to a background isolate
return compute(parseUsers, response.body);
} else {
throw Exception('Failed to load users');
}
}dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(
Uri.parse('https://api.example.com/users'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Offload expensive parsing to a background isolate
return compute(parseUsers, response.body);
} else {
throw Exception('Failed to load users');
}
}