Android 8设备Jetpack Compose捕获Composable时硬件位图异常修复求助
修复Android 8上Composable捕获Picture时的硬件位图异常
问题描述
我实现了一个Modifier扩展方法,用于将Composable内容捕获到Picture实例中,代码如下:
public fun Modifier.captureDrawableContent(picture: Picture, vararg keys: Any?): Modifier = composed { val keyHash = keys.contentHashCode() remember(keyHash) { Modifier.drawWithCache { val width = size.width.toInt() val height = size.height.toInt() onDrawWithContent { val pictureCanvas = Canvas(picture.beginRecording(width, height)) draw(this, layoutDirection, pictureCanvas, size) { this@onDrawWithContent.drawContent() } picture.endRecording() drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) } } } } }
该方法在多数设备上运行正常,但在Android 8(API 26)设备上抛出以下异常:
Fatal Exception: java.lang.IllegalStateException: Software rendering doesn't support hardware bitmaps
异常触发在draw(this, layoutDirection, pictureCanvas, size)代码块内,Android 7.1.1设备无此问题。
问题原因
Android 8的软件渲染器存在限制:无法处理硬件位图。而Compose默认会使用硬件位图提升绘制性能,当我们将绘制命令重定向到基于Picture的软件Canvas时,硬件位图与软件渲染器的冲突就会触发该异常。Android 7.1.1及以下版本的软件渲染器没有这个限制,因此可以正常运行。
修复方案
方案1:强制关闭目标Composable的硬件加速
通过graphicsLayer修饰符强制关闭硬件加速,让Composable使用软件渲染生成兼容的位图,这样录制到Picture时就不会触发异常:
public fun Modifier.captureDrawableContent(picture: Picture, vararg keys: Any?): Modifier = composed { val keyHash = keys.contentHashCode() remember(keyHash) { Modifier // 禁用硬件加速,强制使用软件渲染生成兼容位图 .graphicsLayer(hardwareAccelerationEnabled = false) .drawWithCache { val width = size.width.toInt() val height = size.height.toInt() onDrawWithContent { val pictureCanvas = Canvas(picture.beginRecording(width, height)) draw(this, layoutDirection, pictureCanvas, size) { this@onDrawWithContent.drawContent() } picture.endRecording() drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) } } } } }
方案2:通过中间软件Bitmap中转绘制
如果不想关闭硬件加速,可以先将Composable内容绘制到软件配置的Bitmap中,再将Bitmap内容录制到Picture:
public fun Modifier.captureDrawableContent(picture: Picture, vararg keys: Any?): Modifier = composed { val keyHash = keys.contentHashCode() remember(keyHash) { Modifier.drawWithCache { val width = size.width.toInt() val height = size.height.toInt() onDrawWithContent { // 创建软件配置的Bitmap,确保兼容性 val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val bitmapCanvas = Canvas(bitmap) // 将Composable内容绘制到软件Bitmap draw(this, layoutDirection, bitmapCanvas, size) { this@onDrawWithContent.drawContent() } // 将Bitmap内容录制到Picture val recorder = picture.beginRecording(width, height) recorder.drawBitmap(bitmap, 0f, 0f, null) picture.endRecording() // 绘制到原Canvas(如需显示) drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) } // 回收Bitmap避免内存泄漏 bitmap.recycle() } } } }
注意事项
- 方案1的硬件加速关闭仅影响当前Composable,不会全局生效,适合快照捕获场景,性能影响可控。
- 方案2需要注意
Bitmap的内存回收,避免内存泄漏,尤其是在频繁捕获的场景下。
内容的提问来源于stack exchange,提问作者Serhii Buvaka
相关产品推荐
相关产品推荐

