Android getDrawingCache 过时废弃

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()
相关推荐
Crazy________6 小时前
05Linux内存管理核心原理与运维实战
java·开发语言
Nebula_g6 小时前
JavaSE拓展:工具类Executors
java·开发语言·后端·spring·基础·javase
扶风ff6 小时前
练题簿在线免费刷题:会员线下组卷、Word 试卷与成绩导入,课堂检测更方便
java·开发语言·算法·小程序·word
鱼宵6 小时前
Spring AI 可观测与透明化:traceId 串起全链路,思考过程实时直播给用户
java·人工智能·spring·链路追踪·springai
狗凯之家源码网6 小时前
AI 步数修改提交系统源码应用场景与落地指南
android·数据库·人工智能·运动步数
程序员老陆6 小时前
C++ 多线程通信方式全景:从共享内存到结构化协调
开发语言·c++
Raas1007 小时前
AI网关能做语义缓存吗?MAI Gateway(魔芋企业级AI网关)实战能力深度解读
java·后端·spring
weixin199701080167 小时前
《1688消息服务落地方案:alibaba.message.* 与 Webhook 回调的可靠性与重试策略》(附Python源码)
开发语言·python
天空鸟_时光不老7 小时前
13-亮点提炼:把技术说辞翻译成业务价值
java·spring boot·spring·spring cloud·mybatis
小蒜学长7 小时前
基于SpringBoot+Vue的租房管理系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·租房管理