HarmonyOS6.0开发中的JSON数据处理:从基础到实践
Hello!我是程序员Feri——13年编程老炮,实战派技术人,平时爱拆解编程技巧、分享副业心得,记录程序员的进阶路,AI时代陪大家一起稳稳向前。
在鸿蒙应用开发中,数据交互是核心环节之一——无论是与后端API通信、读取本地配置文件,还是实现组件间的数据传递,都离不开高效的数据格式。
JSON(JavaScript Object Notation)作为轻量级、跨语言的数据交换标准,凭借其简洁性和易解析性,成为鸿蒙开发中的“数据桥梁”。
Feri将从JSON基础入手,详细讲解如何用ArkTS实现JSON处理,并分享实际开发中的实用心得。

一、认识JSON:鸿蒙开发的“通用数据语言”
在学习ArkTS处理JSON之前,我们首先要明确:JSON不是编程语言,而是一种纯文本数据格式,其设计目标是简化数据的存储与传输。
1.1 JSON的核心特性:为何成为鸿蒙开发首选?
JSON能在鸿蒙开发中广泛应用,源于其四大核心优势:
-
轻量简洁:无XML冗余的标签结构,相同数据的JSON体积仅为XML的1/3~1/2,适合鸿蒙设备(尤其是轻量级设备)的网络传输与本地存储。
-
跨语言兼容:JSON语法基于JavaScript对象语法,但独立于编程语言——鸿蒙开发用的ArkTS、后端常用的Java/Go、前端的Vue/React,均原生支持JSON解析,解决了“数据格式互通”问题。
-
人类可读:采用键值对(
key-value)和数组组织数据,结构直观,打开文本编辑器即可直接理解内容,便于调试。 -
易解析:语法规则严格(如键必须用双引号、逗号不能结尾),ArkTS的解析引擎能快速处理,避免解析歧义。
1.2 JSON的语法规则:3分钟掌握核心结构
JSON的核心语法仅包含“对象”和“数组”两种结构,支持6种基础数据类型(字符串、数字、布尔值、null、对象、数组),以下是必须掌握的规则:
(1)基础结构:对象与数组
- 对象(Object):用
{}包裹,内部是键值对集合,格式为"key": value,键必须用双引号(不可用单引号或无引号),键值对用逗号分隔。
示例(鸿蒙配置中的主题色对象):{ "theme": "light", "primaryColor": "#FF007DFF", "isDarkMode": false } - 数组(Array):用
[]包裹,内部是有序数据列表,元素类型可不同(如数字、字符串、对象),元素间用逗号分隔。
示例(鸿蒙应用中的用户列表数组):[ {"userId": 1001, "userName": "鸿蒙开发者"}, {"userId": 1002, "userName": "ArkTS爱好者"} ]
(2)嵌套结构:复杂数据的组织方式
JSON支持对象与数组的嵌套,这是处理复杂数据的关键(如鸿蒙开发中的“课程-学生”关联数据):
{
"courseId": 2024,
"courseName": "鸿蒙应用开发",
"teacher": {"name": "张工", "title": "高级工程师"},
"students": [
{"studentId": 202401, "name": "小李", "score": 92},
{"studentId": 202402, "name": "小王", "score": 88}
]
}
(3)注意事项
-
键必须用双引号(ArkTS解析时,单引号会报错);
-
不能有末尾逗号(如
{"a":1, "b":2,}会解析失败); -
不支持注释(如需注释,需在解析前删除);
-
二进制数据需先转为Base64字符串(JSON仅支持纯文本)。
二、ArkTS实现JSON处理:从基础API到实战封装
鸿蒙开发中,ArkTS基于TypeScript扩展,处理JSON的核心API与JavaScript一致——JSON.stringify()(序列化:对象→JSON字符串)和JSON.parse()(反序列化:JSON字符串→对象),但需结合ArkTS的类型系统和鸿蒙组件特性做适配。
2.1 基础场景:快速实现JSON的“序列化”与“反序列化”
首先从简单场景入手,掌握ArkTS处理基本类型、对象、数组的方法,以下代码可直接在鸿蒙Page组件中运行。
(1)场景1:处理基本类型数组(如数字、字符串数组)
// 鸿蒙Page组件示例
@Entry
@Component
struct JsonBasicDemo {
build() {
Column({ space: 15 }) {
Text("ArkTS JSON基础操作")
.fontSize(18)
.fontWeight(FontWeight.Bold)
// 1. 序列化:数组→JSON字符串
Button("序列化基本类型数组")
.width("90%")
.onClick(() => {
// 定义数字数组
const numArr: number[] = [10, 20, 30, 40];
// 定义字符串数组
const strArr: string[] = ["鸿蒙", "ArkTS", "JSON"];
// 序列化(stringify第二个参数可选,用于格式化输出,便于调试)
const numJson = JSON.stringify(numArr, null, 2); // 2个空格缩进
const strJson = JSON.stringify(strArr, null, 2);
// 打印结果(鸿蒙日志面板查看)
console.log("数字数组JSON:\n" + numJson);
console.log("字符串数组JSON:\n" + strJson);
})
// 2. 反序列化:JSON字符串→数组
Button("反序列化基本类型数组")
.width("90%")
.onClick(() => {
// 模拟后端返回的JSON字符串
const numJsonStr = "[10, 20, 30, 40]";
const strJsonStr = '["鸿蒙", "ArkTS", "JSON"]'; // 注意:JSON字符串内部是双引号,外部用单引号
// 反序列化(指定类型,避免any类型)
const parsedNumArr: number[] = JSON.parse(numJsonStr);
const parsedStrArr: string[] = JSON.parse(strJsonStr);
// 遍历结果
console.log("解析后的数字数组:");
parsedNumArr.forEach(num => console.log(num));
console.log("解析后的字符串数组:");
parsedStrArr.forEach(str => console.log(str));
})
}
.height("100%")
.padding(15)
}
}
(2)场景2:处理自定义对象(如用户、学生对象)
实际开发中,我们更多处理自定义模型(如User、Student),需先定义模型类,再结合stringify和parse:
// 1. 定义模型类(建议单独放在model目录下,便于复用)
export class User {
userId: number = 0; // 默认值,避免null
userName: string = "";
isAdmin: boolean = false;
// 关键:从JSON对象转为User实例(解决parse后类型丢失问题)
static fromJson(json: Partial<User>): User {
const user = new User();
// 赋值(用可选链避免json为undefined时报错)
user.userId = json.userId ?? 0;
user.userName = json.userName ?? "";
user.isAdmin = json.isAdmin ?? false;
return user;
}
}
// 2. 组件中使用
@Entry
@Component
struct JsonObjectDemo {
build() {
Column({ space: 15 }) {
Button("序列化User对象")
.width("90%")
.onClick(() => {
const user = new User();
user.userId = 1001;
user.userName = "鸿蒙开发者";
user.isAdmin = true;
// 序列化对象
const userJson = JSON.stringify(user, null, 2);
console.log("User对象JSON:\n" + userJson);
// 输出结果:
// {
// "userId": 1001,
// "userName": "鸿蒙开发者",
// "isAdmin": true
// }
})
Button("反序列化User对象")
.width("90%")
.onClick(() => {
// 模拟JSON字符串(如后端接口返回)
const userJsonStr = `{
"userId": 1001,
"userName": "鸿蒙开发者",
"isAdmin": true
}`;
// 第一步:解析为Partial<User>(部分属性,避免缺失属性报错)
const jsonObj: Partial<User> = JSON.parse(userJsonStr);
// 第二步:转为User实例(保证类型完整)
const user = User.fromJson(jsonObj);
// 使用解析后的对象
console.log(`用户ID:${user.userId},用户名:${user.userName}`);
})
}
.height("100%")
.padding(15)
}
}
关键说明:为何要写fromJson方法?
直接用JSON.parse(userJsonStr)得到的是any类型(或Partial<User>),无法保证属性完整(如后端少返回一个字段,会导致user.userName为undefined)。fromJson方法通过默认值赋值,确保实例属性始终有有效值,避免运行时错误。
2.2 复杂场景:处理嵌套对象与多层数组
鸿蒙开发中,复杂数据(如“课程-学生-成绩”关联)很常见,需结合数组嵌套对象的解析逻辑,以下是实战示例:
// 1. 定义嵌套模型类
export class Student {
studentId: number = 0;
name: string = "";
birthday: string = ""; // 格式:YYYY-MM-DD
static fromJson(json: Partial<Student>): Student {
const student = new Student();
student.studentId = json.studentId ?? 0;
student.name = json.name ?? "";
student.birthday = json.birthday ?? "1970-01-01";
return student;
}
}
// 课程类(嵌套Student数组)
export class Course {
courseId: number = 0;
courseName: string = "";
students: Student[] = []; // 嵌套Student数组
static fromJson(json: Partial<Course>): Course {
const course = new Course();
course.courseId = json.courseId ?? 0;
course.courseName = json.courseName ?? "";
// 关键:解析嵌套的Student数组
course.students = json.students
? json.students.map(studentJson => Student.fromJson(studentJson))
: [];
return course;
}
}
// 2. 组件中处理复杂JSON
@Entry
@Component
struct JsonNestedDemo {
build() {
Column({ space: 15 }) {
Button("处理嵌套JSON(课程+学生)")
.width("90%")
.onClick(() => {
// 1. 构造复杂对象
const student1 = new Student();
student1.studentId = 202401;
student1.name = "小李";
student1.birthday = "2005-03-15";
const student2 = new Student();
student2.studentId = 202402;
student2.name = "小王";
student2.birthday = "2004-11-20";
const course = new Course();
course.courseId = 2024;
course.courseName = "鸿蒙应用开发";
course.students = [student1, student2];
// 2. 序列化(复杂对象同样适用)
const courseJson = JSON.stringify(course, null, 2);
console.log("嵌套JSON:\n" + courseJson);
// 3. 反序列化(解析嵌套结构)
const jsonObj: Partial<Course> = JSON.parse(courseJson);
const parsedCourse = Course.fromJson(jsonObj);
// 4. 遍历嵌套数据
console.log(`课程名:${parsedCourse.courseName}`);
parsedCourse.students.forEach(student => {
console.log(`学生:${student.name},生日:${student.birthday}`);
});
})
}
.height("100%")
.padding(15)
}
}
2.3 进阶封装:打造鸿蒙JSON工具类(提高复用性)
实际项目中,JSON处理会分散在多个组件,重复写try-catch和解析逻辑会导致代码冗余。建议封装一个JsonUtils工具类,统一处理序列化、反序列化和异常捕获:
// utils/JsonUtils.ets
/**
* 鸿蒙JSON处理工具类:统一处理序列化、反序列化与异常
*/
export class JsonUtils {
/**
* 序列化:对象→JSON字符串
* @param data 要序列化的数据(对象、数组、基本类型)
* @param space 格式化缩进(默认0,不缩进)
* @returns JSON字符串(失败返回空字符串)
*/
static stringify<T>(data: T, space: number = 0): string {
try {
return JSON.stringify(data, null, space);
} catch (error) {
console.error(`JSON序列化失败:${error.message},数据:`, data);
return "";
}
}
/**
* 反序列化:JSON字符串→对象/数组
* @param jsonStr JSON字符串
* @returns 解析后的数据(失败返回undefined)
*/
static parse<T>(jsonStr: string): T | undefined {
// 先校验输入(避免空字符串解析报错)
if (!jsonStr || typeof jsonStr !== "string") {
console.error("JSON反序列化失败:输入不是有效字符串");
return undefined;
}
try {
return JSON.parse(jsonStr) as T;
} catch (error) {
console.error(`JSON反序列化失败:${error.message},字符串:`, jsonStr);
return undefined;
}
}
}
// 使用示例
@Entry
@Component
struct JsonUtilsDemo {
build() {
Column({ space: 15 }) {
Button("用工具类处理JSON")
.width("90%")
.onClick(() => {
const user = new User();
user.userId = 1002;
user.userName = "工具类测试";
// 1. 序列化(用工具类)
const userJson = JsonUtils.stringify(user, 2);
if (!userJson) {
console.error("序列化失败");
return;
}
// 2. 反序列化(用工具类,指定类型)
const jsonObj = JsonUtils.parse<Partial<User>>(userJson);
if (!jsonObj) {
console.error("反序列化失败");
return;
}
const parsedUser = User.fromJson(jsonObj);
console.log(`工具类解析结果:${parsedUser.userName}`);
})
}
.height("100%")
.padding(15)
}
}
工具类优势:
-
统一异常捕获:避免单个组件解析失败导致应用崩溃;
-
简化代码:减少重复的
try-catch和输入校验; -
便于调试:错误日志包含详细的失败原因和数据,快速定位问题。
三、鸿蒙JSON处理的5个实用心得
结合多个鸿蒙项目的开发经验,总结以下5个关键心得,帮你避开坑点、提高效率:
1. 必须重视“类型安全”,避免any类型滥用
鸿蒙ArkTS是强类型语言,直接用JSON.parse()返回any类型,会失去类型校验(如误将userId赋值为字符串,编译时不报错,运行时才崩溃)。
正确做法:
-
定义模型类,用
Partial<T>接收解析结果; -
通过
fromJson方法转为完整实例,补全默认值; -
禁止用
any接收解析结果(除非临时调试)。
2. 异常处理不能少,尤其要防“非法JSON字符串”
实际开发中,JSON字符串可能来自后端接口、本地文件或第三方SDK,存在格式错误(如键用单引号、末尾有逗号)。
避坑方案:
-
用
JsonUtils工具类统一捕获异常,不直接暴露JSON.parse; -
对后端返回的JSON,先校验格式(如用正则判断是否以
{或[开头); -
解析失败时,给用户友好提示(如“数据加载失败,请重试”),而非崩溃。
3. 大数组处理:序列化时避免“循环引用”
如果JSON包含超大数组(如1000条以上数据),直接JSON.stringify可能导致性能问题;若数组元素有循环引用(如A包含B,B又包含A),会直接报错。
优化技巧:
- 大数组序列化时,去掉无用字段(用
stringify的第二个参数“替换函数”过滤):// 只保留user的id和name字段,过滤isAdmin const userJson = JSON.stringify(user, (key, value) => { if (key === "isAdmin") return undefined; // 过滤字段 return value; }, 2); -
避免循环引用:设计模型时,用“ID关联”代替“对象嵌套”(如
course.studentId而非course.student)。
4. 调试技巧:格式化输出+关键日志
JSON调试时,默认的压缩字符串(如{"a":1,"b":2})难以阅读,可通过以下方式提高效率:
-
序列化时加
space参数(如JSON.stringify(data, null, 2)),按2个空格缩进; -
关键步骤打印日志:如“序列化前数据”“解析后数据”,便于定位问题;
-
鸿蒙DevEco Studio的“Logcat”面板支持搜索JSON字段,快速筛选日志。
5. 鸿蒙特有场景:结合数据存储与分布式能力
在鸿蒙开发中,JSON常与以下能力结合,需注意适配:
-
本地存储:用
Preferences存储JSON时,需先转为字符串(Preferences仅支持基本类型和字符串); -
分布式数据:跨设备传输JSON时,确保数据体积不超过分布式能力的限制(一般建议小于100KB);
-
配置文件:鸿蒙应用的
config.json(或module.json5)本质是JSON,修改时需遵守JSON语法(如注释用//需改为json5格式)。
四、总结
JSON作为鸿蒙开发中的“数据通用语言”,是连接前端组件、后端接口、本地存储的关键纽带。掌握其语法规则是基础,用ArkTS实现“模型类+工具类”的封装是核心,而重视类型安全、异常处理和性能优化,则是写出健壮代码的关键。
实际开发中,建议将模型类放在model目录、工具类放在utils目录,形成标准化的JSON处理流程——这样既能提高代码复用性,也能降低后期维护成本。
随着鸿蒙生态的发展,JSON处理还会结合更多场景(如分布式数据同步、跨端数据交互),但核心逻辑始终围绕“序列化准确、反序列化安全”展开,掌握这些基础,就能应对大部分开发需求。
亲,如果你想考取鸿蒙开发者认证,欢迎加入我的班级,有关考证也可随时联系,免费哈!https://developer.huawei.com/consumer/cn/training/classDetail/6ce9d5a998724a849ec634f318107d37?type=1?ha_source=hmosclass&ha_sourceId=89000248
更多推荐




所有评论(0)