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

Flutter使用Image.memory加载图片时如何校验字节有效性避免解码失败

问题背景

现有逻辑为将接口返回的base64格式图片数据校验格式后解码存入SQLite,后续从数据库读取字节数据渲染到UI,逻辑正常时可加载图片或展示默认占位图,但存在部分通过base64格式校验的数据解码为字节后无法作为图片加载,抛出原生层图片解码异常。

现有同步入库逻辑

...
for (var item in items) {
    if (item['photo'] != null) {
        if (isBase64(item['photo'])) {
            Uint8List photo = base64Decode(item['photo']);
            batch.insert('items', {
              'sku': sku,
              'name': name,
              'description': description,
              'price': price,
              'type_name': itemType,
              'pictureBlob': photo
            });
            } else {
            batch.insert('items', {
              'sku': sku,
              'name': name,
              'description': description,
              'price': price,
              'type_name': itemType
            });
        }
    } else {
        batch.insert('items', {
              'sku': sku,
              'name': name,
              'description': description,
              'price': price,
              'type_name': itemType
         });
    }
}
...

现有base64格式校验逻辑

static bool isBase64(dynamic value) {
    if (value.runtimeType == String) {
      final RegExp rx = RegExp(
        r'^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$',
        multiLine: true,
        unicode: true,
      );
      final bool isBase64Valid = rx.hasMatch(value);
      if (isBase64Valid) {
        return true;
      } else {
        return false;
      }
    } else {
      return false;
    }
}

现有UI图片加载逻辑

...
CircleAvatar(
    radius: 65,
    backgroundImage: productItem.pictureBlob != null
    ? Image.memory(productItem.pictureBlob!).image
    : const AssetImage("assets/default.jpg"))
),
...

抛出的异常信息

E/FlutterJNI(10713): Failed to decode image
E/FlutterJNI(10713): android.graphics.ImageDecoder$DecodeException: Failed to create image decoder with message 'unimplemented'Input contained an error.
E/FlutterJNI(10713):    at android.graphics.ImageDecoder.nCreate(Native Method)
E/FlutterJNI(10713):    at android.graphics.ImageDecoder.access$200(ImageDecoder.java:172)
E/FlutterJNI(10713):    at android.graphics.ImageDecoder$ByteBufferSource.createImageDecoder(ImageDecoder.java:242)
E/FlutterJNI(10713):    at android.graphics.ImageDecoder.decodeBitmapImpl(ImageDecoder.java:1870)
E/FlutterJNI(10713):    at android.graphics.ImageDecoder.decodeBitmap(ImageDecoder.java:1863)
E/FlutterJNI(10713):    at io.flutter.embedding.engine.FlutterJNI.decodeImage(FlutterJNI.java:514)
解决方案

问题核心原因:现有正则校验仅能判断字符串符合base64编码规则,无法保证解码后的字节序列为合法可渲染的图片格式,普通文本、损坏的图片文件转成的base64字符串都可以通过正则校验,但解码后无法作为图片加载。
可通过两层防护彻底解决该问题:

  • 入库前增加图片字节有效性校验
    base64解码得到字节数组后,调用Flutter引擎自带的图片解码方法尝试解码,解码成功才将字节存入数据库,解码失败则跳过pictureBlob字段存储,后续走默认图逻辑。示例代码如下:
    import 'dart:ui' as ui;
    
    // 原有base64解码逻辑
    Uint8List photo = base64Decode(item['photo']);
    bool validImage = false;
    try {
      // 尝试解码图片字节,该方法会调用原生层图片解码器,解码成功即说明是合法图片
      await ui.instantiateImageCodec(photo);
      validImage = true;
    } catch (_) {
      validImage = false;
    }
    
    if (validImage) {
      batch.insert('items', {
        'sku': sku,
        'name': name,
        'description': description,
        'price': price,
        'type_name': itemType,
        'pictureBlob': photo
      });
    } else {
      batch.insert('items', {
        'sku': sku,
        'name': name,
        'description': description,
        'price': price,
        'type_name': itemType
      });
    }
    
  • UI加载层增加异常兜底
    替换原有直接取Image.provider的写法,使用Image.memory自带的errorBuilder参数捕获解码异常,异常时直接渲染默认占位图,避免红屏或控制台报错。示例代码如下:
    CircleAvatar(
      radius: 65,
      child: ClipOval(
        child: SizedBox(
          width: 130,
          height: 130,
          child: productItem.pictureBlob != null
            ? Image.memory(
                productItem.pictureBlob!,
                fit: BoxFit.cover,
                errorBuilder: (context, error, stackTrace) {
                  return Image.asset(
                    "assets/default.jpg",
                    fit: BoxFit.cover,
                  );
                },
              )
            : Image.asset("assets/default.jpg", fit: BoxFit.cover),
        ),
      ),
    )
    

不需要额外开发Android原生侧捕获逻辑,上述Dart层的校验和错误兜底已经可以完整捕获原生层抛出的图片解码异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:48:21