kotlin
viewGroup.isDrawingCacheEnabled = true
viewGroup.buildDrawingCache()
是 Android 旧版(API < 28)中用于将 View 转换为 Bitmap 的经典方法 。但在 现代 Android 开发中,这种方式已被弃用(deprecated)且存在严重问题。
⚠️ 重要警告:getDrawingCache() 已在 API 28 被 废弃
从 Android 9 (API 28) 开始:
View.setDrawingCacheEnabled()View.buildDrawingCache()View.getDrawingCache()
全部被标记为 @Deprecated ,官方明确建议 不要再使用。
📌 官方文档说明:
"This method is deprecated. Use {@link #draw(Canvas)} or {@link PixelCopy} instead."
❌ 为什么不要用 DrawingCache?
| 问题 | 说明 |
|---|---|
| 内存泄漏风险 | DrawingCache 内部使用静态 Bitmap 缓存,容易导致 OOM 或 View 引用无法释放 |
| 尺寸限制 | 最大只能生成 4096x4096 的 Bitmap(部分设备更小),大图直接返回 null |
| 硬件加速冲突 | 若 View 启用了硬件加速(默认开启),getDrawingCache() 可能返回空白或黑图 |
| 线程不安全 | 必须在主线程调用,且不能并发使用 |
| 已废弃 | Google 不再维护,未来可能移除 |
✅ 正确替代方案(推荐)
✅ 方案一:使用 Canvas 手动绘制(最常用、兼容性好)
kotlin
fun viewToBitmap(view: View): Bitmap? {
// 测量 & 布局(如果 view 尚未显示)
if (view.width <= 0 || view.height <= 0) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
}
val bitmap = Bitmap.createBitmap(
view.width,
view.height,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
view.draw(canvas)
return bitmap
}
✅ 优点:
- 无废弃警告
- 支持任意大小(受内存限制)
- 兼容硬件加速
- 可在子线程调用(只要 view 已 layout)
✅ 方案二:使用 PixelCopy(仅适用于 Window/Activity 截图)
如果你要截取的是 屏幕上正在显示的 View (如弹窗、SurfaceView 等),可用 PixelCopy(API 24+):
kotlin
fun copyViewToBitmap(activity: Activity, view: View, callback: (Bitmap?) -> Unit) {
val location = IntArray(2)
view.getLocationInWindow(location)
val rect = Rect(location[0], location[1], location[0] + view.width, location[1] + view.height)
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(activity.window, rect, bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
} else {
callback(null)
}
}, Handler(Looper.getMainLooper()))
}
✅ 适合:截图包含 SurfaceView、VideoView、WebView 等特殊内容
❌ 不适合:未显示的 View 或离屏 View
🔧 如果你必须兼容旧代码(不推荐)
若因历史原因暂时无法迁移,至少做以下保护:
kotlin
// 仅在 API < 28 时使用(避免崩溃)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
viewGroup.isDrawingCacheEnabled = true
viewGroup.buildDrawingCache()
val bitmap = viewGroup.drawingCache?.copy(Bitmap.Config.ARGB_8888, false)
viewGroup.isDrawingCacheEnabled = false // ⚠️ 务必关闭!防止内存泄漏
} else {
// 使用 Canvas 方式
val bitmap = viewToBitmap(viewGroup)
}
⚠️ 关键 :用完立即
isDrawingCacheEnabled = false,否则缓存会一直占用内存!
✅ 最佳实践总结
| 场景 | 推荐方法 |
|---|---|
| 普通 View 转 Bitmap(如 ViewGroup、TextView) | ✅ Canvas + view.draw() |
| 屏幕上已显示的复杂内容(含 SurfaceView) | ✅ PixelCopy |
| 生成分享图、海报、长图 | ✅ 先 measure/layout,再 Canvas.draw() |
| 任何新项目 | ❌ 不要用 DrawingCache |
💡 示例:完整安全转换函数(Kotlin)
kotlin
fun View.toBitmap(): Bitmap? {
return try {
if (width <= 0 || height <= 0) {
measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
layout(0, 0, measuredWidth, measuredHeight)
}
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
draw(Canvas(bitmap))
bitmap
} catch (e: Exception) {
e.printStackTrace()
null
}
}
// 使用
val bitmap = myViewGroup.toBitmap()