解决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
相关产品推荐
相关产品推荐

