Flutter中如何流式读取HTTP响应大JSON并映射至对象类?
Flutter流式处理大JSON HTTP响应并逐步映射到自定义对象
当然可以,Flutter结合Dart标准库和http包就能实现流式处理HTTP响应,边接收数据边解析JSON并映射到自定义对象,避免一次性加载大文件导致内存占用过高。
核心思路
- 获取HTTP流式响应:通过
http包的send()方法获取StreamedResponse,它的stream属性是字节流,支持分块读取。 - 字节流转字符流:用
utf8.decoder将字节流转换为UTF-8字符流,方便JSON解析。 - 分块解析JSON:使用
dart:convert中JsonDecoder的startChunkedConversion()方法,支持分块解析JSON数据,无需等待完整响应。 - 自定义Sink处理解析结果:实现
ChunkedConversionSink,在每一块JSON数据解析完成后,将其映射为自定义对象并立即处理(比如存入列表、数据库)。
代码示例
假设我们要处理一个大的JSON数组,每个元素是用户数据,映射到User类:
首先定义自定义对象类:
class User { final int id; final String name; User({required this.id, required this.name}); factory User.fromJson(Map<String, dynamic> json) { return User( id: json['id'] as int, name: json['name'] as String, ); } }
然后实现流式处理逻辑:
import 'dart:convert'; import 'package:http/http.dart' as http; void streamLargeJsonToObjects() async { final url = Uri.parse('https://your-api.com/large-user-list.json'); final request = http.Request('GET', url); final streamedResponse = await request.send(); // 将字节流转换为UTF-8字符流 final charStream = streamedResponse.stream.transform(utf8.decoder); // 初始化JSON分块解析器 final jsonDecoder = JsonDecoder(); final userSink = _UserProcessingSink((User user) { // 每解析出一个User对象就立即处理,比如打印、存库 print('已处理用户: ${user.name} (ID: ${user.id})'); }); // 开始分块转换与处理 await charStream.transform(jsonDecoder.startChunkedConversion(userSink)).drain(); } // 自定义Sink,处理分块解析后的JSON数据 class _UserProcessingSink extends ChunkedConversionSink<dynamic> { final void Function(User) onUserProcessed; List<dynamic>? _incompleteArray; _UserProcessingSink(this.onUserProcessed); @override void add(dynamic chunk) { // 处理JSON数组场景:如果是完整数组,直接遍历转换;如果是分块的数组元素,暂存后处理 if (chunk is List) { for (final json in chunk) { onUserProcessed(User.fromJson(json as Map<String, dynamic>)); } } else if (_incompleteArray != null) { _incompleteArray!.add(chunk); } // 处理单个JSON对象场景(如果接口返回的是单个对象而非数组) else if (chunk is Map<String, dynamic>) { onUserProcessed(User.fromJson(chunk)); } } @override void addError(Object error, [StackTrace? stackTrace]) { print('JSON解析出错: $error'); } @override void close() { // 收尾处理未完成的数组元素 if (_incompleteArray != null) { for (final json in _incompleteArray!) { onUserProcessed(User.fromJson(json as Map<String, dynamic>)); } _incompleteArray = null; } } }
注意事项
- 如果你的JSON结构更复杂(比如嵌套对象、多层数组),需要在
_UserProcessingSink的add()方法中针对性处理JSON片段的结构,确保正确识别和转换。 - 可以结合本地数据库(如sqflite),在
onUserProcessed回调中直接将对象存入数据库,避免大量数据占用内存。 - 记得处理网络错误和JSON解析错误,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Uoel
相关产品推荐
相关产品推荐

