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

Flutter使用image_gallery_saver存图UI卡顿,compute调用报错求助

问题描述

使用image_gallery_saver保存图片时,UI线程会根据图片大小出现不同程度的卡顿。尝试用compute创建新线程执行保存逻辑时,抛出以下错误:

在platform_channel.dart中,由以下代码抛出:
BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
异常信息:{_CastError} Null check operator used on a null value

当前使用的代码:

try {
  //CheckPermission
  if (await Permission.storage.request().isGranted) {
    final result = await SaveImageToKoi(post.fimgUrl!.url!);
    print(result);
    if (result != null)
      BotToast.showText(text: "Success");
    else
      BotToast.showText(text: "Error");
  }
} catch (e) {}
},

dynamic SaveImageToKoi (koi_url) async {
  print(koi_url);
  var response = await Dio().get(
      koi_url,
      options: Options(responseType: ResponseType.bytes));

  final result = await ImageGallerySaver.saveImage(
      Uint8List.fromList(response.data),
      quality: 100);
}

错误原因

compute会把任务放到独立的Dart隔离区(Isolate)执行,但image_gallery_saver底层依赖的平台通道(MethodChannel)只能在主隔离区使用——非主隔离区没有初始化ServicesBinding,导致ServicesBinding.instance为null,触发空检查错误。

UI卡顿的核心原因是:你把图片下载、数据转换、平台保存全放在了主线程,大图片的下载和字节转换操作会阻塞UI线程。

解决方案

拆分任务:将纯Dart实现的图片下载、字节转换逻辑放到compute中执行,平台保存操作(ImageGallerySaver.saveImage)留在主线程处理。既规避了隔离区调用平台通道的错误,又能让主线程不被耗时操作阻塞。

修改后的代码示例:

try {
  // 检查存储权限
  if (await Permission.storage.request().isGranted) {
    // 将下载逻辑放到后台隔离区执行
    final imageBytes = await compute(_downloadImageBytes, post.fimgUrl!.url!);
    if (imageBytes != null) {
      // 保存图片操作留在主线程执行
      final result = await ImageGallerySaver.saveImage(
        imageBytes,
        quality: 100,
      );
      print(result);
      BotToast.showText(text: result != null ? "保存成功" : "保存失败");
    } else {
      BotToast.showText(text: "图片下载失败");
    }
  }
} catch (e) {
  print(e);
  BotToast.showText(text: "操作异常");
}
},

// 纯Dart函数,仅负责下载图片并返回字节数据,用于在compute中执行
Uint8List? _downloadImageBytes(String koiUrl) async {
  try {
    print(koiUrl);
    var response = await Dio().get(
      koiUrl,
      options: Options(responseType: ResponseType.bytes),
    );
    return Uint8List.fromList(response.data);
  } catch (e) {
    print(e);
    return null;
  }
}

补充说明

  • compute仅支持执行纯Dart逻辑,不能包含任何原生插件调用,因为隔离区无法访问主隔离区的平台通信机制。
  • 拆分后,耗时的下载和字节转换在后台隔离区运行,主线程只处理权限检查、触发保存和用户提示,不会再出现UI卡顿。

内容的提问来源于stack exchange,提问作者Dr_Black

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:30:41