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

解决Bitmap.createBitmap方法中内存不足异常的方案

解决View转Bitmap时的OutOfMemoryError问题

你的OOM问题源于要创建的Bitmap内存占用过高:ARGB_8888格式下需分配约42MB内存,但当前可用内存仅9MB。以下是几种可行的解决思路:

1. 降低Bitmap色彩配置

ARGB_8888每个像素占4字节,若打印场景不需要透明度,换成RGB_565(每个像素2字节)可直接减半内存占用:

val returnedBitmap = Bitmap.createBitmap(
    v.measuredWidth,
    v.measuredHeight, Bitmap.Config.RGB_565
)

如果对色彩精度要求极低,也可尝试ARGB_4444,但该配置已被官方标记为废弃,仅作备选。

2. 根据打印需求缩放Bitmap

打印无需和屏幕分辨率一致,可结合打印机DPI和实际打印尺寸计算合理的缩放比例,缩小Bitmap尺寸:

private fun loadBitmapFromView(context: Context, v: View, printDpi: Int = 300, printWidthInInch: Float = 8.5f): Bitmap {
    val dm = context.resources.displayMetrics
    v.measure(
        View.MeasureSpec.makeMeasureSpec(dm.widthPixels, View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
    )
    v.layout(0, 0, v.measuredWidth, v.measuredHeight)

    // 计算目标宽度:打印英寸数 × 打印机DPI
    val targetWidth = (printWidthInInch * printDpi).toInt()
    val scale = targetWidth.toFloat() / v.measuredWidth
    val targetHeight = (v.measuredHeight * scale).toInt()

    val returnedBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.RGB_565)
    val c = Canvas(returnedBitmap)
    // 缩放画布后绘制View,保证内容比例正确
    c.scale(scale, scale)
    v.draw(c)
    return returnedBitmap
}

3. 分块绘制合并(适配超大型View)

如果必须保留原尺寸,可将View拆分为多个小区域分别绘制,再合并为完整Bitmap,同时及时回收临时块释放内存:

private fun loadBitmapFromViewInChunks(context: Context, v: View, chunkHeight: Int = 1000): Bitmap {
    val dm = context.resources.displayMetrics
    v.measure(
        View.MeasureSpec.makeMeasureSpec(dm.widthPixels, View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
    )
    v.layout(0, 0, v.measuredWidth, v.measuredHeight)

    val fullWidth = v.measuredWidth
    val fullHeight = v.measuredHeight
    val fullBitmap = Bitmap.createBitmap(fullWidth, fullHeight, Bitmap.Config.RGB_565)
    val fullCanvas = Canvas(fullBitmap)

    var currentTop = 0
    while (currentTop < fullHeight) {
        val currentChunkHeight = min(chunkHeight, fullHeight - currentTop)
        // 创建临时块Bitmap
        val chunkBitmap = Bitmap.createBitmap(fullWidth, currentChunkHeight, Bitmap.Config.RGB_565)
        val chunkCanvas = Canvas(chunkBitmap)
        
        // 平移画布,绘制View的对应区域
        chunkCanvas.translate(0f, -currentTop.toFloat())
        v.draw(chunkCanvas)
        
        // 将块绘制到完整Bitmap
        fullCanvas.drawBitmap(chunkBitmap, 0f, currentTop.toFloat(), null)
        
        // 回收临时块,释放内存
        chunkBitmap.recycle()
        currentTop += currentChunkHeight
    }
    return fullBitmap
}

4. 额外内存优化要点

  • 及时回收不再使用的Bitmap:调用bitmap.recycle()并置为null,帮助GC释放内存
  • 移至子线程处理:大Bitmap的创建和绘制耗时,避免阻塞主线程导致ANR
  • 校验View测量结果:确认View没有被意外测量出超大尺寸(比如嵌套ScrollView时的高度异常)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:47:29