今天碰到一个上传较大的视频文件到S3引发闪退的问题。经查此问题产生的原因是内存溢出,连个闪退日志都没有。
这个上传使用的是第三方的插件,我是用 uploadFileStream 来上传文件的,查看其实现代码,它使用的是http插件的 http.StreamedRequest, 它会把文件分块读出来,添加分块签名,再使用 request.sink.add(xxx) 加入缓冲区, 最后调用 request.send() 来完成发送。
这样问题就来了,它会把整个文件外加签名信息都放到缓冲区,意味着文件越大,也就占用更多的内存,最终导致崩溃的发生。
由于需要对文件进行签名处理,不能直接使用 dio 插件文件上传方式(说不定dio也会有同样的问题,还没来得及细品)。http 插件也没有提供边读边处理边发送的方法,问题限入卡顿状态,在网上搜索半天也没有找到一个解决方案,最后想想,能不能直接用最基础的 HttpClient 来解决呢?
因为平常主要用dio和http这两个插件,没有用过HttpClient,没有认真研究过它。这个时候想起来它,就马上细品起来,最终真的找到的解决方案。还真是越低级的封装,关键时候越能解决问题。
下面给出使用 HttpClient 解决上面问题的关键代码:
//初始化一个Http客户端,并加入自定义Header
var req =await HttpClient().putUrl(uri);
headers.forEach((key, value) {
req.headers.add(key, value);
});//读文件
var s =await file.open();var x = 0;var size =file.lengthSync();var chunkSize = 65536;while (x = chunkSize ? chunkSize : size -x;
val=s.readSync(_len).toList();
x= x +_len;//处理数据块
val =proc(val);//加入http发送缓冲区
req.add(val);//立即发送并清空缓冲区
await req.flush();
}
await s.close();//文件发送完成
await req.close();//获取返回数据
final response =await req.done;//其它处理逻辑
print("response statusCode: ${resp.statusCode}");
经测试,用上面方法上传大文件,内存占用平稳,最后真机测试,也没有再闪退。
原文:https://www.cnblogs.com/yangyxd/p/13094925.html