Android SQLite触发BlobTooBigException 插入图片时如何限制文件大小
问题根源
Android 系统内置的 CursorWindow 默认最大分配内存为 2MB,只要单条查询结果中包含的 Blob 字段超过这个阈值就会抛出 SQLiteBlobTooBigException,和你查询的返回条数无关,因此添加 limit 限制无法解决问题。
最优解决方案:SQLite 存储图片 Uri 而非 Blob
你当前的相机逻辑已经将拍摄的原图存入了系统 MediaStore,拿到了永久有效的 image_uri,完全不需要将图片二进制流存入 SQLite,这个方案不会影响你现有的裁剪、原图展示需求,是移动端存储图片的通用最佳实践。
改造步骤:
- 修改 SQLite 表结构,将原本
cc_image、id_image两个 BLOB 类型字段改为 TEXT 类型,用于存储图片 Uri 的字符串形式 - 修改插入逻辑,插入时直接传入你已有的
image_uri.toString(),不需要再把图片转成 byte 数组 - 查询时取出字段值转成 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
相关产品推荐
相关产品推荐

