mcpField
F
flutter-implement-json-serialization

flutter-implement-json-serialization

github.com/flutter开发3.1k37.8k 次安装2 天前更新
代码仓库

关于 flutter-implement-json-serialization

面向 Flutter 开发者的手动 JSON 序列化技能,涵盖模型转换、网络响应解析和大型数据的后台处理。

主要功能

  1. 01实现模型的 fromJson 和 toJson
  2. 02为 JSON 解码添加类型转换
  3. 03使用 compute 在 isolate 中解析
  4. 04校验 HTTP 状态并处理失败
  5. 05为序列化方法编写单元测试

适用场景

  1. 01为 Dart 模型添加 JSON 转换
  2. 02解析 HTTP 请求返回的数据
  3. 03在后台处理大型 JSON 文档

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/flutter/agent-plugins --skill flutter-implement-json-serialization

安装后在 Claude Code 中输入/flutter-implement-json-serialization确认已加载。

详细介绍

在 Flutter 中手动序列化 JSON

目录

核心指南

  • 导入 dart:convert:使用 Flutter 内置的 dart:convert 库手动编码(jsonEncode)和解码(jsonDecode)JSON。
  • 确保类型安全:始终将 jsonDecode() 返回的 dynamic 结果转换为预期类型,对象通常为 Map<String, dynamic>,数组通常为 List<dynamic>。
  • 封装序列化逻辑:定义包含与 JSON 结构对应属性的普通模型类。在模型中实现 fromJson 工厂构造函数和 toJson 方法。
  • 处理后台解析:如果要解析大型 JSON 文档(执行时间 > 16ms),请使用 Flutter 的 compute() 函数,将解析逻辑转移到单独的 isolate,以避免 UI 卡顿。
  • 失败时抛出异常:处理 HTTP 响应时,如果状态码不表示成功(例如,不是 200 OK 或 201 Created),则抛出异常。不要返回 null。

工作流:实现可序列化模型

使用此检查清单为数据模型实现手动 JSON 序列化。

任务进度:

  • 定义包含 final 属性的普通模型类。
  • 实现 factory Model.fromJson(Map<String, dynamic> json) 构造函数。
  • 实现 Map<String, dynamic> toJson() 方法。
  • 为这两种序列化方法编写单元测试。
  • 运行验证器 -> 检查类型不匹配错误 -> 修复类型转换逻辑。
  1. 定义模型:创建一个属性与 JSON 键相匹配的类。
  2. 实现 fromJson:从 Map 中提取值,并将它们转换为相应的 Dart 类型。使用模式匹配或显式类型转换。
  3. 实现 toJson:返回一个 Map<String, dynamic>,将类属性映射回对应的 JSON 字符串键。
  4. 验证:运行单元测试,确保类型安全、自动补全和编译时异常处理都能正常工作。

工作流:获取和解析 JSON

从网络请求获取并解析 JSON 时,请使用此条件工作流。

任务进度:

  • 执行 HTTP 请求。
  • 验证响应状态码。
  • 确定解析策略(同步或使用 isolate)。
  • 解码 JSON 并将其映射到模型。
  1. 执行请求:使用 http 包执行网络调用。
  2. 验证响应:
    • 如果 response.statusCode == 200(POST 请求为 201),则继续解析。
    • 如果状态码表示失败,则抛出 Exception。
  3. 确定解析策略:
    • 如果解析的是小型负载(例如,单个对象),则在主线程上同步解析。
    • 如果解析的是大型负载(例如,包含数千个对象的数组),则使用 compute(parseFunction, response.body) 在后台 isolate 中解析。
  4. 解码并映射:将解码后的 JSON 传递给模型的 fromJson 构造函数。

示例

高保真模型实现
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,
    };
  }
}
同步解析(小型负载)
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');
  }
}
后台解析(大型负载)
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');
  }
}

评论

支持 Markdown