Flutter类型转换错误:Null不是int的子类型,求解决方案
环境信息
- Flutter 3.3.9 • stable渠道
- 框架 • 修订版本b8f7f1f986(2周前)• 2022-11-23 06:43:51 +0900
- 引擎 • 修订版本8f2221fbef
- 工具 • Dart 2.18.5 • DevTools 2.15.0
问题描述
我花了数小时尝试解决JSON解析相关错误,但未能成功,恳请告知解决方法。当前使用Flutter空安全特性,以下是我使用的模型代码、API请求响应及生成的代码:
base_response_model.dart
import 'package:json_annotation/json_annotation.dart'; part 'base_response_model.g.dart'; @JsonSerializable() class BaseResponseModel { final int page; @JsonKey(name: 'page_size') final int pageSize; final int total; final int pages; @JsonKey(name: 'prev_page', defaultValue: 0) final dynamic prevPage; @JsonKey(name: 'next_page', defaultValue: 0) final dynamic nextPage; BaseResponseModel({ required this.page, required this.pageSize, required this.total, required this.pages, required this.prevPage, required this.nextPage, }); factory BaseResponseModel.fromJson(Map<String, dynamic> json) => _$BaseResponseModelFromJson(json); Map<String, dynamic> toJson() => _$BaseResponseModelToJson(this); }
get_municipalities_by_province_response_model.dart
import 'package:delivery/app/data/models/andariego/andariego_models/municipality_model.dart'; import 'package:delivery/app/data/models/andariego/andariego_response_models/base_response_model.dart'; import 'package:json_annotation/json_annotation.dart'; part 'get_municipalities_by_province_response_model.g.dart'; @JsonSerializable() class GetMunicipalitiesByProvinceResponseModel extends BaseResponseModel { final List<MunicipalityModel> data; GetMunicipalitiesByProvinceResponseModel({ required super.page, required super.pageSize, required super.total, required super.pages, required super.prevPage, required super.nextPage, required this.data, }); factory GetMunicipalitiesByProvinceResponseModel.fromJson( Map<String, dynamic> json) => _$GetMunicipalitiesByProvinceResponseModelFromJson(json); @override Map<String, dynamic> toJson() => _$GetMunicipalitiesByProvinceResponseModelToJson(this); }
municipality_model.dart
import 'package:delivery/app/data/models/andariego/andariego_models/base_andariego_model.dart'; import 'package:json_annotation/json_annotation.dart'; part 'municipality_model.g.dart'; @JsonSerializable() class MunicipalityModel extends BaseAndariegoModel { final int parent; MunicipalityModel({ required super.id, required super.name, required this.parent, }); factory MunicipalityModel.fromJson(Map<String, dynamic> json) => _$MunicipalityModelFromJson(json); @override Map<String, dynamic> toJson() => _$MunicipalityModelToJson(this); }
API响应示例(api_response.json)
{ "page": 1, "page_size": 20, "total": 11, "pages": 1, "prev_page": null, "next_page": null, "data": [ { "id": 1188, "name": "Consolación del Sur", "parent": 58 }, { "id": 1132, "name": "Guane", "parent": 58 }, { "id": 1125, "name": "La Palma", "parent": 58 }, { "id": 1124, "name": "Los Palacios", "parent": 58 }, { "id": 1186, "name": "Mantua", "parent": 58 }, { "id": 1182, "name": "Minas de Matahambre", "parent": 58 }, { "id": 1189, "name": "Pinar del Rio", "parent": 58 }, { "id": 1165, "name": "Sandino", "parent": 58 }, { "id": 1133, "name": "San Juan y Martínez", "parent": 58 }, { "id": 1187, "name": "San Luis", "parent": 58 }, { "id": 1169, "name": "Viñales", "parent": 58 } ] }
自动生成的代码
base_response_model.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'base_response_model.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** BaseResponseModel _$BaseResponseModelFromJson(Map<String, dynamic> json) => BaseResponseModel( page: json['page'] as int, pageSize: json['page_size'] as int, total: json['total'] as int, pages: json['pages'] as int, prevPage: json['prev_page'] ?? 0, nextPage: json['next_page'] ?? 0, ); Map<String, dynamic> _$BaseResponseModelToJson(BaseResponseModel instance) => <String, dynamic>{ 'page': instance.page, 'page_size': instance.pageSize, 'total': instance.total, 'pages': instance.pages, 'prev_page': instance.prevPage, 'next_page': instance.nextPage, };
get_municipalities_by_province_response_model.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'get_municipalities_by_province_response_model.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** GetMunicipalitiesByProvinceResponseModel _$GetMunicipalitiesByProvinceResponseModelFromJson( Map<String, dynamic> json) => GetMunicipalitiesByProvinceResponseModel( page: json['page'] as int, pageSize: json['page_size'] as int, total: json['total'] as int, pages: json['pages'] as int, prevPage: json['prev_page'] ?? 0, nextPage: json['next_page'] ?? 0, data: (json['data'] as List<dynamic>) .map((e) => MunicipalityModel.fromJson(e as Map<String, dynamic>)) .toList(), ); Map<String, dynamic> _$GetMunicipalitiesByProvinceResponseModelToJson( GetMunicipalitiesByProvinceResponseModel instance) => <String, dynamic>{ 'page': instance.page, 'page_size': instance.pageSize, 'total': instance.total, 'pages': instance.pages, 'prev_page': instance.prevPage, 'next_page': instance.nextPage, 'data': instance.data, };
municipality_model.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'municipality_model.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** MunicipalityModel _$MunicipalityModelFromJson(Map<String, dynamic> json) => MunicipalityModel( id: json['id'] as int, name: json['name'] as String, parent: json['parent'] as int, ); Map<String, dynamic> _$MunicipalityModelToJson(MunicipalityModel instance) => <String, dynamic>{ 'id': instance.id, 'name': instance.name, 'parent': instance.parent, };
解决方案
从代码和API响应来看,问题出在prevPage和nextPage的空值处理上:
- API返回的
prev_page和next_page是null,但defaultValue仅在字段不存在时生效,字段存在但值为null时不会触发默认值;同时dynamic类型会导致空安全下的类型隐患。 - 生成代码中的
json['prev_page'] ?? 0虽能处理null,但类型不明确,不符合空安全规范。
修改步骤如下:
1. 修正父类模型的字段定义
将prevPage和nextPage改为可空int?类型,移除defaultValue,并调整构造函数参数:
import 'package:json_annotation/json_annotation.dart'; part 'base_response_model.g.dart'; @JsonSerializable() class BaseResponseModel { final int page; @JsonKey(name: 'page_size') final int pageSize; final int total; final int pages; @JsonKey(name: 'prev_page') final int? prevPage; @JsonKey(name: 'next_page') final int? nextPage; BaseResponseModel({ required this.page, required this.pageSize, required this.total, required this.pages, this.prevPage, this.nextPage, }); factory BaseResponseModel.fromJson(Map<String, dynamic> json) => _$BaseResponseModelFromJson(json); Map<String, dynamic> toJson() => _$BaseResponseModelToJson(this); }
2. 更新子类构造函数
因为父类参数不再是required,子类也要对应调整:
import 'package:delivery/app/data/models/andariego/andariego_models/municipality_model.dart'; import 'package:delivery/app/data/models/andariego/andariego_response_models/base_response_model.dart'; import 'package:json_annotation/json_annotation.dart'; part 'get_municipalities_by_province_response_model.g.dart'; @JsonSerializable() class GetMunicipalitiesByProvinceResponseModel extends BaseResponseModel { final List<MunicipalityModel> data; GetMunicipalitiesByProvinceResponseModel({ required super.page, required super.pageSize, required super.total, required super.pages, super.prevPage, super.nextPage, required this.data, }); factory GetMunicipalitiesByProvinceResponseModel.fromJson( Map<String, dynamic> json) => _$GetMunicipalitiesByProvinceResponseModelFromJson(json); @override Map<String, dynamic> toJson() => _$GetMunicipalitiesByProvinceResponseModelToJson(this); }
3. 重新生成序列化代码
执行命令重新生成代码:
flutter pub run build_runner build --delete-conflicting-outputs
修改后即可正确处理API返回的null值,完全符合Flutter空安全规范,避免类型转换错误。
内容的提问来源于stack exchange,提问作者rroviedo
相关产品推荐
相关产品推荐

