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

Android SQLite触发BlobTooBigException 插入图片时如何限制文件大小

问题根源

Android 系统内置的 CursorWindow 默认最大分配内存为 2MB,只要单条查询结果中包含的 Blob 字段超过这个阈值就会抛出 SQLiteBlobTooBigException,和你查询的返回条数无关,因此添加 limit 限制无法解决问题。

最优解决方案:SQLite 存储图片 Uri 而非 Blob

你当前的相机逻辑已经将拍摄的原图存入了系统 MediaStore,拿到了永久有效的 image_uri,完全不需要将图片二进制流存入 SQLite,这个方案不会影响你现有的裁剪、原图展示需求,是移动端存储图片的通用最佳实践。

改造步骤:

  1. 修改 SQLite 表结构,将原本 cc_image、id_image 两个 BLOB 类型字段改为 TEXT 类型,用于存储图片 Uri 的字符串形式
  2. 修改插入逻辑,插入时直接传入你已有的 image_uri.toString(),不需要再把图片转成 byte 数组
  3. 查询时取出字段值转成 Uri 即可正常使用,和你现有跨页传图、加载原图、裁剪的逻辑完全兼容,不需要额外修改

备选方案:压缩图片后再存 Blob

如果确实需要将图片二进制存入 SQLite(比如用于列表页快速加载缩略图),可以修改图片转字节数组的逻辑,通过降低分辨率、切换压缩格式两个维度缩小体积。你原有存在MediaStore的原图不会被修改,需要裁剪、展示原图时继续使用原来的image_uri即可,不受压缩逻辑影响。
修改后的代码如下:

public static byte[] imageViewToByte(ImageView image) {
    Bitmap originBitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();
    // 1. 先降低分辨率,最大宽度限制为1080px,列表展示完全足够
    int maxWidth = 1080;
    int width = originBitmap.getWidth();
    int height = originBitmap.getHeight();
    float scale = Math.min((float) maxWidth / width, (float) maxWidth / height);
    if (scale < 1) {
        int newWidth = (int) (width * scale);
        int newHeight = (int) (height * scale);
        originBitmap = Bitmap.createScaledBitmap(originBitmap, newWidth, newHeight, true);
    }
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    // 2. 切换为JPEG有损压缩,质量80对普通照片来说肉眼几乎看不出区别,体积比PNG小3-5倍
    originBitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);
    byte[] byteArray = stream.toByteArray();
    // 回收临时Bitmap避免内存泄漏
    if (originBitmap != null && !originBitmap.isRecycled()) {
        originBitmap.recycle();
    }
    return byteArray;
}

改造后生成的字节数组基本都在几百KB以内,不会触发CursorWindow的大小限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:24:04