You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何流式读取HTTP响应大JSON并映射至对象类?

Flutter流式处理大JSON HTTP响应并逐步映射到自定义对象

当然可以,Flutter结合Dart标准库和http包就能实现流式处理HTTP响应,边接收数据边解析JSON并映射到自定义对象,避免一次性加载大文件导致内存占用过高。

核心思路

  1. 获取HTTP流式响应:通过http包的send()方法获取StreamedResponse,它的stream属性是字节流,支持分块读取。
  2. 字节流转字符流:用utf8.decoder将字节流转换为UTF-8字符流,方便JSON解析。
  3. 分块解析JSON:使用dart:convert中JsonDecoder的startChunkedConversion()方法,支持分块解析JSON数据,无需等待完整响应。
  4. 自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 08:34:56