CachedNetworkImage引发Firebase Crashlytics崩溃问题咨询
问题详情
在Firebase Crashlytics中持续收到来自cached_network_image包的两类崩溃异常:
ImageLoader.loadImageAsync.<fn>:io.flutter.plugins.firebase.crashlytics.FlutterError - Exception: Invalid image data. Error thrown resolving an image codec.ImageLoader.loadBufferAsync.<fn>:io.flutter.plugins.firebase.crashlytics.FlutterError - Exception: Invalid image data. Error thrown resolving an image codec.
堆栈信息
- 第一类异常堆栈:
Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError
Exception: Invalid image data. Error thrown resolving an image codec..instantiateImageCodecWithSize (dart:ui)
ImageLoader.loadImageAsync.(_image_loader.dart:68)
ImageLoader._load (_image_loader.dart:129)
new MultiImageStreamCompleter.(multi_image_stream_completer.dart:26)
- 第二类异常堆栈:
Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError
Exception: Invalid image data. Error thrown resolving an image codec..instantiateImageCodecWithSize (dart:ui)
ImageLoader.loadBufferAsync.(_image_loader.dart:68)
ImageLoader._load (_image_loader.dart:129)
new MultiImageStreamCompleter.(multi_image_stream_completer.dart:26)
错误标识
flutter_error_exception: Exception: Invalid image dataflutter_error_reason: thrown resolving an image codec
我的代码实现
CachedNetworkImage( width: ScreenHelper().getScreenWidth(0.35), height: ScreenHelper().getScreenHeight(0.18), progressIndicatorBuilder: (context, url, progress) => SkeletonContainer.square( width: ScreenHelper().getScreenWidth(0.35), height: ScreenHelper().getScreenHeight(0.18), borderRadius: const BorderRadius.all(Radius.circular(10)), ), fit: BoxFit.fill, imageUrl: imgUrl, errorWidget: (context, url, error) => Image.asset( AppAsset.appLogo, gaplessPlayback: true, fit: BoxFit.contain, ), )
疑问
- 该异常在
cached_network_image包中是否常见? - 崩溃事件已累积数千次,但
errorWidget本应处理图像加载失败的显示,为何仍会持续触发异常? - 是不是我对该包的使用方式有误?
解答
1. 该异常是否常见?
这个异常在cached_network_image的使用场景里确实不算罕见,核心原因是网络返回的内容并非合法的图片数据:比如图片链接失效返回404页面的HTML内容、接口错误返回JSON格式的错误信息、或者网络请求中途中断导致数据不完整,这些都会让Flutter的图片编解码器无法解析,进而抛出Invalid image data异常。
2. 为什么ErrorWidget没拦截住异常?
errorWidget只能处理cached_network_image上层封装的业务错误(比如网络请求超时、缓存读取失败、HTTP状态码错误等),但这类崩溃是在Flutter引擎底层的instantiateImageCodecWithSize方法抛出的,属于未被上层代码捕获的原生异常。Firebase Crashlytics会自动捕获Flutter中所有未被处理的错误,所以即使UI上已经显示了errorWidget,底层的异常依然会被上报到Crashlytics。
3. 使用方式是否有误?
你的代码写法本身没有问题,但可以通过以下优化减少这类崩溃上报:
- 提前校验链接有效性:在传入
imageUrl前,确保链接指向的是合法的图片资源,避免传入无效、过期的链接; - 拦截网络响应:在网络请求层判断返回的
Content-Type是否为图片类型(如image/jpeg、image/png),如果不是则直接返回错误,不将非图片数据传给图片解码器; - 手动捕获异常:可以自定义
ImageProvider,在加载逻辑中用try-catch包裹编解码步骤,避免异常向上抛出; - 升级包版本:更新
cached_network_image到最新版本,官方可能在后续版本中优化了这类异常的捕获逻辑。
内容的提问来源于stack exchange,提问作者Eric Low

