Flutter中如何通过Dio动态指定请求返回的数据模型?
问题描述
在进行网络数据交互时,如何确保dio返回的响应数据符合特定的数据模型?
例如,所有响应内容均为application/JSON类型,并符合以下规则:
- 字段
code为0到1000之间的整数。 - 字段
message为可选提示文本,可能为null。 - 字段
timestamp为当前时间的秒级时间戳。 - 字段
data为可选数据,可为任意类型,可能为null。
因此,定义了如下模型:
class ResponseModel<T> { late final int code; late final int timestamp; late final String? message; late final T? data; }
通过dio获取的所有响应数据都存储在_InternalLinkedHashMap类型的Map中,无法通过如下方法签名指定返回类型来完成转换:
Future<Response<ResponseModel>> request() { // 使用`dio`访问网络数据并返回 }
那么,如何在dio中将响应数据存储到ResponseModel模型中?
已尝试方案:查阅相关文档后,了解到可以通过命名构造函数进行数据转换,但由于该模型包含泛型类型,无法编写标准的转换函数。
相关代码:
class ResponseModel<T> { /* 部分字段 */ ResponseModel.fromJson(Map<String, dynamic> json) { code = json['code'] as int; timestamp = json['timestamp'] as int; if (null != json['message']) { message = json['message'] as String; } // 如何转换data? } }
解决方案
1. 改造泛型模型的构造函数
给ResponseModel的命名构造函数添加数据转换回调,用来处理泛型data的解析,不同接口可传入对应转换逻辑:
class ResponseModel<T> { final int code; final int timestamp; final String? message; final T? data; // 用初始化列表替代late,避免空安全隐患 ResponseModel({ required this.code, required this.timestamp, this.message, this.data, }); // 添加data解析回调参数 ResponseModel.fromJson( Map<String, dynamic> json, T? Function(dynamic)? dataParser, ) : code = json['code'] as int, timestamp = json['timestamp'] as int, message = json['message'] as String?, data = dataParser != null ? dataParser(json['data']) : json['data'] as T?; }
2. 在Dio请求中使用模型
发起请求时,传入对应data的解析函数即可:
// 示例:假设data是User类型 class User { final String name; final int age; User.fromJson(Map<String, dynamic> json) : name = json['name'], age = json['age']; } Future<ResponseModel<User>> getUser() async { final response = await Dio().get('your-api-url'); return ResponseModel<User>.fromJson( response.data, (data) => data != null ? User.fromJson(data) : null, ); } // 如果data是基础类型(String/int等),可直接省略解析函数 Future<ResponseModel<String>> getStringData() async { final response = await Dio().get('another-api-url'); return ResponseModel<String>.fromJson(response.data, null); }
3. 全局拦截器统一处理(可选)
如果所有接口都要使用该模型,可通过Dio拦截器统一解析,减少重复代码:
class ResponseInterceptor extends Interceptor { @override void onResponse(Response response, ResponseInterceptorHandler handler) { // 先统一校验code、timestamp等字段合法性 if (response.data is Map<String, dynamic>) { // 简单示例:若无需强类型解析data,直接包装 final model = ResponseModel<dynamic>.fromJson(response.data, null); response.data = model; } handler.next(response); } } // 初始化Dio时添加拦截器 final dio = Dio()..interceptors.add(ResponseInterceptor());
注意事项
- 优先使用初始化列表替代
late final,避免空安全问题。 - 解析
data时要处理null场景,防止类型转换异常。 - 若需复杂泛型解析,可结合
json_serializable库的JsonConverter实现更灵活的类型转换。
内容的提问来源于stack exchange,提问作者vorbote
相关产品推荐
相关产品推荐

