Flutter使用Image库调整图片大小速度极慢,如何优化代码提升处理效率?
问题分析
- 核心性能问题:所有图片解码、缩放、编码、写文件等CPU密集型操作全部运行在Flutter主Isolate(UI线程),会阻塞UI渲染同时导致处理耗时大幅增加
- 冗余处理逻辑:没有使用image_picker原生提供的缩放压缩能力,直接加载相机输出的全尺寸原图(通常单张4000*3000分辨率以上,大小5M+)进行dart侧解码处理,本身就有大量不必要的性能开销
- 线程阻塞操作:使用
writeAsBytesSync同步写文件,会直接阻塞当前线程,进一步拉长处理时间 - 逻辑漏洞:图片选择异常时
pickedImage为null,但后续处理逻辑没有做判空,会直接触发空指针异常
优化方案
1. 最优方案:直接使用image_picker原生能力处理(性能提升最明显)
image_picker的pickImage方法本身自带原生层面的尺寸压缩、质量压缩能力,处理速度是dart侧image库处理的3-10倍,不需要额外引入第三方图片处理库就能满足需求:
void _selectImage() async { XFile? checkDataImage; try { checkDataImage = await _imagePicker.pickImage( source: ImageSource.camera, maxWidth: 500, // 原生层直接输出宽度500的图片,无需后续dart侧resize imageQuality: 90, // 原生层直接完成JPG质量压缩 ); if (checkDataImage != null) { setState(() { pickedImage = checkDataImage; // 直接用系统处理好的文件上传,不需要额外处理 _imageUpload = File(checkDataImage.path); }); } } catch (err) { print(err); pickedImage = null; } }
2. 自定义处理场景方案:子Isolate跑图片处理逻辑
如果有滤镜、裁剪等自定义图片处理需求,必须要在dart侧操作图片,就把所有图片处理逻辑移到独立子Isolate运行,避免占用主线程:
// 图片处理逻辑需要写成顶级函数或静态方法,才能传入compute Future<File> resizeImage(List args) async { final XFile pickedImage = args[0]; final String tempPath = args[1]; final rand = Random().nextInt(999999999); final imageBytes = await pickedImage.readAsBytes(); final image = Img.decodeImage(imageBytes); final smallerImg = Img.copyResize(image!, width: 500); final compressImg = File('$tempPath/image_$rand.jpg'); // 用异步API写文件,不要用同步方法 await compressImg.writeAsBytes(Img.encodeJpg(smallerImg, quality: 90)); return compressImg; } void _selectImage() async { try { final checkDataImage = await _imagePicker.pickImage(source: ImageSource.camera); if (checkDataImage != null) { print(checkDataImage.name); print(checkDataImage.path); setState(() { pickedImage = checkDataImage; }); final tempDir = await getTemporaryDirectory(); // 把处理逻辑扔到子Isolate运行 final compressImg = await compute(resizeImage, [checkDataImage, tempDir.path]); if (mounted) { setState(() { _imageUpload = compressImg; }); } } } catch (err) { print(err); pickedImage = null; } }
3. 其他细节优化
- 所有图片处理逻辑必须放在
checkDataImage != null的判断分支内,避免空指针异常 - 所有IO操作全部使用异步API,禁止使用同步IO方法阻塞线程
- 图片编码可根据业务场景适当调低quality参数,进一步降低处理和上传耗时
内容的提问来源于stack exchange,提问作者Nyoman Gunartha
相关产品推荐
相关产品推荐

