Dart JSON解析空值检查错误解决及Model创建最佳实践
问题:Dart JSON解析空值错误及Model类最佳实践
我在Dart项目中进行JSON数据解析时遇到以下问题:
一、相关代码与数据
1. 待解析的JSON数据
{ "data": { "getJobs": [ { "id": "124", "title": "another", "addressId": null, "status": "OPEN", "companyAddress": null, "industry": "IT", "jobType": "PART_TIME", "salaryMin": 10000, "salaryMax": 20000, "deadline": "2021-04-19T00:00:00.000Z", "isFeatured": false, "description": "test check" } ] } }
2. quicktype生成的Model类
import 'dart:convert'; GetJobsResponseModel getJobsResponseModelFromJson(String str) => GetJobsResponseModel.fromJson(json.decode(str)); String getJobsResponseModelToJson(GetJobsResponseModel data) => json.encode(data.toJson()); class GetJobsResponseModel { Data? data; GetJobsResponseModel({ this.data, }); factory GetJobsResponseModel.fromJson(Map<String, dynamic> json) => GetJobsResponseModel( data: json["data"] == null ? null : Data.fromJson(json["data"]), ); Map<String, dynamic> toJson() => { "data": data?.toJson(), }; } class Data { List<GetJob>? getJobs; Data({ this.getJobs, }); factory Data.fromJson(Map<String, dynamic> json) => Data( getJobs: json["getJobs"] == null ? [] : List<GetJob>.from(json["getJobs"]!.map((x) => GetJob.fromJson(x))), ); Map<String, dynamic> toJson() => { "getJobs": getJobs == null ? [] : List<dynamic>.from(getJobs!.map((x) => x.toJson())), }; } class GetJob { String? id; String? title; dynamic addressId; String? status; dynamic companyAddress; String? industry; String? jobType; int? salaryMin; int? salaryMax; DateTime? deadline; bool? isFeatured; String? description; GetJob({ this.id, this.title, this.addressId, this.status, this.companyAddress, this.industry, this.jobType, this.salaryMin, this.salaryMax, this.deadline, this.isFeatured, this.description, }); factory GetJob.fromJson(Map<String, dynamic> json) => GetJob( id: json["id"], title: json["title"], addressId: json["addressId"], status: json["status"], companyAddress: json["companyAddress"], industry: json["industry"], jobType: json["jobType"], salaryMin: json["salaryMin"], salaryMax: json["salaryMax"], deadline: json["deadline"] == null ? null : DateTime.parse(json["deadline"]), isFeatured: json["isFeatured"], description: json["description"], ); Map<String, dynamic> toJson() => { "id": id, "title": title, "addressId": addressId, "status": status, "companyAddress": companyAddress, "industry": industry, "jobType": jobType, "salaryMin": salaryMin, "salaryMax": salaryMax, "deadline": deadline?.toIso8601String(), "isFeatured": isFeatured, "description": description, }; }
3. Service层代码
Future<List<GetJob>> getAllJobs(){ try{ // 省略请求逻辑 final data = result.data?['data']['getJobs'] as List; final List<GetJob> jobs = data.map((job) => GetJob.fromJson(job)).toList(); return jobs; } catch(e){ print('Error fetching data: $e'); rethrow; } }
二、遇到的问题
运行时抛出错误:Error fetching data: Null check operator used on a null value,返回空列表,UI无法展示id、title等字段。需要解决这个错误,同时想了解创建Model类的最佳方式。
解决方案
一、解决空值错误
错误根源在于Service层的链式取值result.data?['data']['getJobs']:虽然result.data用了可空访问符,但后续的['data']和['getJobs']若前置节点为null,直接取值会触发空值错误,且强制转as List会在数据为null时崩溃。
方案1:逐层空值判断
修改Service层代码,对每个节点做空值校验:
Future<List<GetJob>> getAllJobs() async { try{ // 省略请求逻辑,确保result是请求返回的响应对象 if (result.data == null) { return []; } final responseData = result.data as Map<String, dynamic>; final dataNode = responseData['data'] as Map<String, dynamic>?; if (dataNode == null) { return []; } final getJobsList = dataNode['getJobs'] as List?; if (getJobsList == null) { return []; } final List<GetJob> jobs = getJobsList.map((job) => GetJob.fromJson(job as Map<String, dynamic>)).toList(); return jobs; } catch(e){ print('Error fetching data: $e'); rethrow; } }
方案2:利用生成的Model类解析
直接用quicktype生成的Model类处理整个JSON,避免手动链式取值,更安全简洁:
Future<List<GetJob>> getAllJobs() async { try{ // 假设responseBody是接口返回的原始JSON字符串 final responseModel = getJobsResponseModelFromJson(responseBody); return responseModel.data?.getJobs ?? []; } catch(e){ print('Error fetching data: $e'); rethrow; } }
二、创建Model类的最佳方式
1. 优先使用代码生成工具
- quicktype:当前使用的工具,支持多语言,能快速生成带空值处理的Model类,适合快速开发。生成时可配置空安全选项,确保代码符合Dart空安全规范。
- json_serializable:Dart官方推荐的代码生成库,配合
build_runner使用,高度可定制,支持自定义解析逻辑,适合大型项目。使用步骤:- 添加依赖到
pubspec.yaml:dependencies: json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.4 json_serializable: ^6.7.0 - 编写实体类并添加注解:
import 'package:json_annotation/json_annotation.dart'; part 'get_job.g.dart'; @JsonSerializable() class GetJob { final String? id; final String? title; final dynamic addressId; // 其他字段... GetJob({this.id, this.title, this.addressId, /* 其他参数 */}); factory GetJob.fromJson(Map<String, dynamic> json) => _$GetJobFromJson(json); Map<String, dynamic> toJson() => _$GetJobToJson(this); } - 运行命令生成代码:
dart run build_runner build
- 添加依赖到
2. 手动编写Model类(简单场景)
若JSON结构简单,可手动编写Model类,但需严格遵循Dart空安全规范,对可选字段用?标记,解析时做空值判断。
3. 核心注意事项
- 避免不必要的
!强制非空操作,严格处理空值; - 对日期、枚举等特殊类型,添加自定义解析逻辑(如json_serializable可用
@JsonKey注解处理日期); - 保持Model类单一职责,仅负责数据解析与序列化。
内容的提问来源于stack exchange,提问作者Dhiraj
相关产品推荐
相关产品推荐

