鸿蒙Flutter JSON解析与序列化:JSON错误处理与容错机制
·




概述
在实际开发中,JSON解析过程中可能遇到各种错误,如格式错误、类型不匹配、字段缺失等。完善的错误处理机制是保证应用稳定性的关键。本文将详细介绍JSON解析中常见的错误类型、捕获策略和容错机制,帮助开发者构建健壮的应用。
1. JSON解析常见错误类型
1.1 FormatException - 格式错误
当JSON字符串不符合语法规范时抛出:
// 错误示例1:缺少引号
String invalidJson1 = '{"name": 张三}';
// 错误示例2:多余逗号
String invalidJson2 = '{"name": "张三",}';
// 错误示例3:缺少闭合括号
String invalidJson3 = '{"name": "张三"';
1.2 TypeError - 类型错误
当类型转换失败时抛出:
Map<String, dynamic> data = {'age': '25'};
int age = data['age'] as int; // TypeError: String cannot be cast to int
1.3 NullError - 空值错误
当访问null对象的属性时抛出:
Map<String, dynamic> data = {'user': null};
Map<String, dynamic> user = data['user'] as Map<String, dynamic>; // 可能导致错误
1.4 RangeError - 范围错误
当访问数组越界时抛出:
List<dynamic> list = [1, 2, 3];
var item = list[5]; // RangeError
2. 错误捕获策略
2.1 基础try-catch
void parseJson(String jsonString) {
try {
Map<String, dynamic> data = jsonDecode(jsonString);
String name = data['name'] as String;
print('解析成功: $name');
} catch (e) {
print('解析失败: $e');
}
}
2.2 分类捕获
void parseJson(String jsonString) {
try {
Map<String, dynamic> data = jsonDecode(jsonString);
String name = data['name'] as String;
int age = data['age'] as int;
print('解析成功');
} on FormatException catch (e) {
print('JSON格式错误: $e');
} on TypeError catch (e) {
print('类型转换错误: $e');
} on Exception catch (e) {
print('其他异常: $e');
} catch (e) {
print('未知错误: $e');
}
}
2.3 使用rethrow重新抛出
void parseJson(String jsonString) {
try {
Map<String, dynamic> data = jsonDecode(jsonString);
} catch (e) {
print('记录错误日志: $e');
rethrow; // 重新抛出,让上层处理
}
}
3. 容错解析模式
3.1 安全类型转换
String? safeString(dynamic value) {
if (value is String) {
return value;
}
return null;
}
int? safeInt(dynamic value) {
if (value is int) {
return value;
}
if (value is double) {
return value.toInt();
}
return null;
}
3.2 默认值处理
factory Weather.fromJson(Map<String, dynamic> json) {
return Weather(
city: json['city'] as String? ?? '未知城市',
temperature: (json['temperature'] as num?)?.toInt() ?? 0,
humidity: (json['humidity'] as num?)?.toInt() ?? 50,
);
}
3.3 可选字段处理
class Weather {
final String city;
final int temperature;
final String? description; // 可选字段
Weather({
required this.city,
required this.temperature,
this.description,
});
factory Weather.fromJson(Map<String, dynamic> json) {
return Weather(
city: json['city'] as String? ?? '未知城市',
temperature: (json['temperature'] as num?)?.toInt() ?? 0,
description: json['description'] as String?,
);
}
}
3.4 嵌套对象容错
factory Weather.fromJson(Map<String, dynamic> json) {
return Weather(
city: json['city'] as String? ?? '未知城市',
wind: _parseWind(json['wind']),
);
}
static Wind _parseWind(dynamic json) {
if (json is Map<String, dynamic>) {
return Wind.fromJson(json);
}
return Wind(direction: '未知', speed: 0);
}
3.5 数组容错
static List<Forecast> _parseForecast(dynamic json) {
if (json is List<dynamic>) {
return json
.whereType<Map<String, dynamic>>()
.map((e) => Forecast.fromJson(e))
.toList();
}
return [];
}
4. 错误处理最佳实践
4.1 创建统一的错误处理类
class JsonParseError {
final String message;
final String? field;
final dynamic rawValue;
final StackTrace? stackTrace;
JsonParseError({
required this.message,
this.field,
this.rawValue,
this.stackTrace,
});
String toString() {
return 'JsonParseError: $message${field != null ? ' (字段: $field)' : ''}';
}
}
4.2 使用Result模式
enum ParseStatus { success, failure }
class ParseResult<T> {
final ParseStatus status;
final T? data;
final JsonParseError? error;
ParseResult.success(this.data)
: status = ParseStatus.success,
error = null;
ParseResult.failure(this.error)
: status = ParseStatus.failure,
data = null;
}
ParseResult<Weather> parseWeather(String jsonString) {
try {
Map<String, dynamic> data = jsonDecode(jsonString);
Weather weather = Weather.fromJson(data);
return ParseResult.success(weather);
} on FormatException catch (e) {
return ParseResult.failure(
JsonParseError(message: 'JSON格式错误: $e'),
);
} on TypeError catch (e) {
return ParseResult.failure(
JsonParseError(message: '类型转换错误: $e'),
);
}
}
4.3 错误日志记录
void logError(dynamic error, StackTrace stackTrace, String context) {
print('[$context] 错误: $error');
print('堆栈: $stackTrace');
// 可以发送到远程日志服务
}
5. 完整示例:容错解析器
import 'dart:convert';
class Weather {
final String city;
final int temperature;
final int humidity;
final Wind? wind;
final List<Forecast> forecast;
Weather({
required this.city,
required this.temperature,
required this.humidity,
this.wind,
required this.forecast,
});
factory Weather.fromJson(Map<String, dynamic> json) {
return Weather(
city: _parseString(json['city'], '城市'),
temperature: _parseInt(json['temperature'], '温度'),
humidity: _parseInt(json['humidity'], '湿度'),
wind: _parseWind(json['wind']),
forecast: _parseForecast(json['forecast']),
);
}
static String _parseString(dynamic value, String fieldName) {
if (value is String) {
return value;
}
print('警告: $fieldName 类型错误,使用默认值');
return '未知';
}
static int _parseInt(dynamic value, String fieldName) {
if (value is int) {
return value;
}
if (value is double) {
return value.toInt();
}
print('警告: $fieldName 类型错误,使用默认值');
return 0;
}
static Wind? _parseWind(dynamic json) {
if (json is Map<String, dynamic>) {
return Wind.fromJson(json);
}
return null;
}
static List<Forecast> _parseForecast(dynamic json) {
if (json is List<dynamic>) {
return json
.whereType<Map<String, dynamic>>()
.map((e) => Forecast.fromJson(e))
.toList();
}
return [];
}
}
class Wind {
final String direction;
final int speed;
Wind({required this.direction, required this.speed});
factory Wind.fromJson(Map<String, dynamic> json) {
return Wind(
direction: json['direction'] as String? ?? '未知',
speed: (json['speed'] as num?)?.toInt() ?? 0,
);
}
}
class Forecast {
final String date;
final int high;
final int low;
Forecast({required this.date, required this.high, required this.low});
factory Forecast.fromJson(Map<String, dynamic> json) {
return Forecast(
date: json['date'] as String? ?? '未知日期',
high: (json['high'] as num?)?.toInt() ?? 0,
low: (json['low'] as num?)?.toInt() ?? 0,
);
}
}
6. 鸿蒙平台错误处理
6.1 平台特定错误
在鸿蒙平台上,需要注意以下特殊情况:
- 网络请求超时导致的不完整JSON
- 平台特定的字符编码问题
- 内存限制导致的大型JSON解析失败
6.2 异步错误处理
Future<Weather?> fetchWeather(String url) async {
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) {
throw Exception('HTTP错误: ${response.statusCode}');
}
return Weather.fromJson(jsonDecode(response.body));
} on SocketException catch (e) {
print('网络连接错误: $e');
return null;
} on FormatException catch (e) {
print('JSON格式错误: $e');
return null;
} catch (e) {
print('未知错误: $e');
return null;
}
}
7. 总结
完善的错误处理机制是构建健壮应用的关键。通过分类捕获异常、安全类型转换、提供默认值等策略,可以有效提高JSON解析的容错能力。在鸿蒙平台上,还需要考虑网络和平台特定的错误情况。下一章将介绍JSON格式化与美化的方法。
核心知识点回顾
- JSON解析常见错误:FormatException、TypeError、NullError、RangeError
- 使用try-catch进行错误捕获,分类处理不同类型的异常
- 使用as?进行安全类型转换,避免TypeError
- 使用??提供默认值,处理缺失或null字段
- 对于嵌套对象和数组,提供容错解析逻辑
- 使用Result模式统一处理成功和失败状态
- 添加错误日志记录,便于问题排查
更多推荐



所有评论(0)