JSON数据处理:字符串序列化与反序列化实战(20)

在 HarmonyOS 应用开发中,JSON 数据处理是网络请求、本地数据持久化以及跨模块通信的核心基础。由于 HarmonyOS 的本地存储(如 Preferences、PersistentStorage)以及网络传输通常只支持基础数据类型(如 string),开发者必须熟练掌握对象与 JSON 字符串之间的转换。

以下梳理 JSON 序列化与反序列化实战:

一、 基础序列化与反序列化

对于简单的对象或数组,可以直接使用内置的 JSON 对象进行转换。

  • 序列化(对象转字符串) :使用 JSON.stringify()
  • 反序列化(字符串转对象) :使用 JSON.parse()

实战示例(网络请求场景)

在发送 POST 请求时,需要将请求体序列化为 JSON 字符串;在接收响应时,需要将返回的 JSON 字符串解析为具体的接口类型。

TypeScript 复制代码
import { http } from '@kit.NetworkKit';

interface User { id: number; name: string; }

async function fetchUser(userId: number): Promise<User> {
  let httpRequest = http.createHttpRequest();
  try {
    // 1. 序列化:将对象转为 JSON 字符串作为请求体
    let requestBody = JSON.stringify({ userId: userId });
    
    let result = await httpRequest.request('https://api.example.com/user', {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'application/json' },
      extraData: requestBody
    });
    
    // 2. 反序列化:将服务端返回的 JSON 字符串解析为 User 对象
    if (result.responseCode === 200) {
      let user = JSON.parse(result.result as string) as User;
      return user;
    }
  } catch (error) {
    console.error('请求失败:', error);
    throw error;
  } finally {
    httpRequest.destroy();
  }
}

二、 高级序列化:指定部分属性

在实际业务中,有时出于安全或性能考虑,不希望将对象的所有属性都暴露或存储。JSON.stringify() 的第二个参数 replacer 支持传入一个字符串数组,用于指定需要序列化的属性。

实战示例

TypeScript 复制代码
interface Person { name: string; age: number; city: string; }
let obj: Person = { name: 'John', age: 30, city: 'ChongQing' };

// 仅序列化 name 属性
let jsonStr = JSON.stringify(obj, ['name']); 
console.info(jsonStr); // 输出: {"name":"John"}

三、 本地持久化存储中的 JSON 处理

HarmonyOS 提供的轻量级键值对存储 Preferences 仅支持 stringnumberboolean 等基础类型。存储复杂对象(如列表、自定义类)时,必须进行序列化。

最佳实践:封装数据访问层(Repo)

为了避免在业务逻辑中频繁处理字符串转换,建议将序列化逻辑封装在数据访问层中,确保上层业务始终操作的是强类型对象:

TypeScript 复制代码
export class TodayRepo {
  // 读取并反序列化
  async get(dateKey: string): Promise<DailyEntry | null> {
    const raw = await this.prefs.getString(toKey(dateKey));
    if (!raw) return null;
    try {
      const parsed = JSON.parse(raw) as DailyEntry;
      return isValidEntry(parsed) ? parsed : null; // 增加合法性校验
    } catch (_err) {
      return null;
    }
  }

  // 序列化并写入
  async set(entry: DailyEntry): Promise<void> {
    await this.prefs.setString(toKey(entry.date), JSON.stringify(entry));
  }
}

四、 核心避坑指南:带方法的对象数组

这是开发中最容易引发崩溃的场景。JSON.stringify()JSON.parse() 只能处理纯数据,无法保留对象的原型链(即类中的方法) 。如果直接将带有方法的对象数组存入 PersistentStorage,读取后调用方法会导致应用崩溃。

解决方案

  1. 无方法的纯数据类 :直接 JSON.parse() 解析即可。
  2. 带方法的类 :反序列化后,必须通过 map 遍历数据,调用类的构造函数重新实例化对象,以恢复原型链。

实战示例

TypeScript 复制代码
class Student {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  // 带有方法的类
  selfIntroduction(): string {
    return `I am ${this.name}, ${this.age} years old.`;
  }
}

// 存储时:转为字符串
let jsonStr = JSON.stringify([new Student('Tom', 16)]);

// 读取时:必须重新构造对象数组
let dataArr = JSON.parse(jsonStr);
let studentArr = dataArr.map((item: Student) => new Student(item.name, item.age));

// 此时才能安全调用方法
studentArr[0].selfIntroduction(); 

五、 特殊数据结构处理:HashMap

JSON.stringify() 默认不支持直接对 HashMap 进行操作。如果需要将 HashMap 序列化(例如传递给 Native 侧或进行网络传输),需要先将其转换为普通的 Record 对象:

TypeScript 复制代码
function map2rec(map: HashMap<string, ESObject>): Record<string, ESObject> {
  let rec: Record<string, ESObject> = {};
  map.forEach((value: ESObject, key: string) => {
    if (value instanceof HashMap) {
      rec[key] = map2rec(value); // 递归处理嵌套的 HashMap
    } else {
      rec[key] = value;
    }
  });
  return rec;
}

let myRec = map2rec(hashMap);
let str = JSON.stringify(myRec); // 正常序列化

在掌握了基础的 JSON 序列化、反序列化以及对象方法恢复等实战技巧后,针对 HarmonyOS 的企业级开发,我们还需要应对状态管理持久化、跨设备流转、第三方工具库集成以及底层字节流转换等更高级的数据处理场景。以下从四个维度进行深度扩展:

一、 状态管理持久化:V1 与 V2 的 JSON 处理差异

在 HarmonyOS 中,将复杂对象存入 AppStoragePersistentStorage 时,底层都会进行 JSON 序列化。不同版本的状态管理在底层机制上存在显著差异:

  1. V1 时代的 PersistentStorage :它仅支持基础类型。存储对象或数组时,开发者必须手动调用 JSON.stringify() 转为字符串,读取时再用 JSON.parse() 还原。若对象包含方法,还需通过 map 遍历重新调用构造函数(如前文所述)。
  2. V2 时代的 PersistenceV2 :引入了"劫持-代理"双阶段机制。开发者只需使用 @ObservedV2@Trace 装饰器,框架会在编译期注入拦截器。当数据发生改变时,PersistenceV2 会在后台自动进行脏值检查、JSON 序列化,并通过异步队列合并 I/O 操作写入磁盘。
    • 避坑指南PersistenceV2 对数据类型要求极其严苛,仅支持基础类型及其构成的 ArrayObject。如果试图将 PixelMap(图片对象)或复杂的闭包函数塞入,运行时会直接报错。

二、 跨设备流转:Base64 字节流与 JSON 的无缝转换

在 HarmonyOS NEXT 的 Share Kit(碰一碰分享)或跨设备流转(onContinue)场景中,复杂的 JSON 数据通常不能直接以明文传输,而是需要转换为高抗干扰的字节流:

  1. 发送端(序列化与编码) :首先将内存中的结构化 JSON 对象序列化为字符串,然后利用 util.TextEncoder 将其转化为 Uint8Array 字节流,最后进行 Base64 编码,拼装在自定义的外链(如 aeroplan://import_plan)中。
  2. 接收端(拦截与反序列化) :当 B 设备通过 Scheme 拦截到外链后,提取 Base64 字符串,解码还原为 JSON 字符串,再解析为具体的业务对象,最终写入本地关系型数据库(RDB)。
    这种设计将跨应用的数据流转操作大幅压缩,消除了繁琐的手动复制粘贴体验。

三、 第三方工具库集成:harmony-utils

除了系统自带的 JSON 对象,在实际工程中,推荐使用社区成熟的工具库(如 @pura/harmony-utils)来简化复杂的 JSON 操作。该库提供了丰富的 API:

  • 类型安全转换 :通过 JSONUtil.jsonToBean(jsonStr, User) 可以直接将 JSON 字符串安全地转换为指定的 Class 实例,避免了手动 as 断言的繁琐。
  • 复杂结构解析 :支持 jsonToArray(转数组)、jsonToMap(转 Map)以及 mapToJsonStr(Map 转字符串)。
  • 格式校验 :提供 isJSONStr() 方法,在处理外部传入的不可靠数据时,可先进行合法性校验,防止 JSON.parse() 抛出异常导致应用崩溃。

四、 底层数据处理:超长字符串与二进制流

在某些极客场景下(如大文件传输、长文本加密),普通的 JSON 字符串可能会遇到 URL 长度限制或内存瓶颈。此时需要结合底层 API 进行处理:

  • TextEncoder / TextDecoder :当 JSON 字符串过长时,可以利用鸿蒙的 util.TextEncoder 将字符串直接映射为 Uint8Array。这种直接内存映射操作比普通的循环转换性能高出 60% 以上,非常适合在网络请求的 extraData 中传输二进制格式的 JSON 数据。
  • 流式处理 :对于超大 JSON 文件,避免一次性 JSON.parse() 导致主线程 OOM(内存溢出),应考虑结合文件流(fs)进行分块读取,或采用 SAX 模式的流式解析器,边读取边处理节点数据。
相关推荐
木木子2220 小时前
# 待办事项应用深度解析:ForEach 列表渲染与 CRUD 操作实战
windows·华为·harmonyos
2501_943782351 天前
【共创季稿事节】摇骰子:用 ArkTS 实现随机动画与交互反馈
运维·nginx·交互·harmonyos·鸿蒙·鸿蒙系统
zjxcq5201 天前
【共创季稿事节】鸿蒙原生ArkTS布局之道——layoutWeight权重分配机制深度解析
华为·harmonyos
2501_943782351 天前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
想你依然心痛1 天前
AtomCode 在 HarmonyOS 开发环境中的表现测评
跨平台·harmonyos·arkts·信创·国产系统
2501_943782351 天前
【共创季稿事节】 倒计时器:时分秒选择器与定时器的协同工作
前端·华为·harmonyos·鸿蒙·鸿蒙系统
TrisighT1 天前
Electron 鸿蒙 PC 上做本地搜索,Fuse.js 比 SQLite 快 6 倍——但我愣是选了最慢的方案
electron·sqlite·harmonyos
独守一片天1 天前
HarmonyOS 6.1.0 Call Service 来电识别与安全通信怎么设计?
安全·华为·harmonyos
AI创界者1 天前
【硬核教程】鸿蒙 HarmonyOS 4.2 / 4.3 完美配置 GMS 运行环境(纯净版/不弹窗/全机型通用)
华为·harmonyos
2501_942389551 天前
小米寥寥几家车企设计汽车顶棚
华为·编辑器·时序数据库·harmonyos