Android 9及以上叠加Bitmap报软件渲染不支持硬件位图崩溃问题
问题解决说明
崩溃原因
Android 8.0(API 26)起系统新增了硬件位图(Bitmap.Config.HARDWARE)优化,默认加载的Bitmap会优先使用硬件位图存储,这类位图仅支持在硬件加速的Canvas上绘制。就算你提前关闭了页面硬件加速配置,只要参与绘制的base、blendBitmap或者copy生成的结果Bitmap是硬件位图,用软件Canvas绘制时就会触发该异常。
解决方案
方案1:在叠加方法内统一转换为软件位图
修改overlay方法,强制将所有参与绘制的Bitmap转为非硬件的ARGB_8888格式,代码如下:
private fun overlay(base: Bitmap, blend: Bitmap): Bitmap { return try { // 先将传入的两个Bitmap转为软件位图,避免硬件位图导致报错 val softBase = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && base.isHardware) { base.copy(Bitmap.Config.ARGB_8888, true) } else { base } val softBlend = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && blend.isHardware) { blend.copy(Bitmap.Config.ARGB_8888, true) } else { blend } val result: Bitmap = softBase.copy(Bitmap.Config.ARGB_8888, true) val p = Paint() p.xfermode = PorterDuffXfermode(PorterDuff.Mode.ADD) p.shader = BitmapShader(softBlend, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) val c = Canvas() c.setBitmap(result) c.drawBitmap(softBase, 0f, 0f, null) c.drawRect(0f, 0f, softBase.width.toFloat(), softBase.height.toFloat(), p) // 回收临时生成的位图,减少内存占用 if (softBase != base) softBase.recycle() if (softBlend != blend) softBlend.recycle() result } catch (e: Exception) { println(e.message.toString()) base } }
方案2:加载位图时直接禁用硬件位图
如果是通过BitmapFactory加载源图,加载时就指定配置禁用硬件位图,避免后续转换开销:
val options = BitmapFactory.Options() options.inPreferredConfig = Bitmap.Config.ARGB_8888 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 禁止优先使用硬件位图配置 options.inPreferredConfig = Bitmap.Config.ARGB_8888 options.inIsConfigPreferenceMutable = true } // 加载图片时传入该options val bitmap = BitmapFactory.decodeResource(resources, R.drawable.your_image, options)
注意事项
如果不需要全局关闭硬件加速,仅针对该叠加逻辑的话,也可以单独对绘制的View开启硬件加速,也能解决该问题,不需要额外转换Bitmap。
内容的提问来源于stack exchange,提问作者ahmad bajwa
相关产品推荐
相关产品推荐

