安卓禁用硬件加速_Android 优化之硬件加速

原理

可以简单理解为通过底层软件代码,将 CPU 不擅长的图形计算转换为 GPU 专用指令,由 GPU 完成。

当目标 API 级别大于等于 14 时,硬件加速默认开启。

控制硬件加速

我们可以在以下 4 个级别控制硬件加速:

Application

在清单文件种,加入以下属性,为整个应用启用硬件加速:

Activity

在清单文件中对应的 标签下添加下面代码:

Window

window 级别不能停用硬件加速。

window.setFlags(

WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,

WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED

)

View

View 不能启用硬件加速,只能停用硬件加速,如下:

view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

DisplayList

DisplayList 是一个基本绘制元素,包含元素原始属性(位置、尺寸、角度、透明等),当 view 的一些属性改变(scale 、rotate、alpha、translate),只需把属性更新给 GPU,不需要生成新的 DisplayList。

RenderNode

一个 RenderNode 包含若干个 DisplayList,通常一个 RendeNode 对应一个 View,包含 View 及其 View 的所有 DisplayList。

软件绘制与硬件绘制

软件绘制

绘制内容会被 CPU 转换成实际的像素(由 Bitmap 来承载),然后直接渲染到屏幕上。

硬件绘制

绘制的内容会转换成 GPU 的操作保存下来(由 DisplayList 来承载),再交给 GPU 来操作。

cfc79ee27eaa

来自美团

场景1中,无论是否开启硬件加速,遍历 view 树并都会走 Draw 路径。硬件加速后 Draw 路径不做实际绘制工作,只是构建 DisplayList,复杂的绘制计算被 GPU 分担。

场景2 中,TextView 设置前后尺寸位置不变,不会触发重新 Layout。

软件绘制中,TextView 所在的区域及为脏区,由于 TextView 有透明区域,遍历 View 树的过程中,和脏区重叠的多数 View 都要重绘,包括与之重叠的的兄弟节点和他们的父节点,不要绘制的 View 在 draw(Canvas canvas, ViewGroup parent, long drawingTime) 方法中判断直接返回。

判断 View 是否经过硬件加速

View.isHardwareAccelerated()

当 view 已经附着到启用硬件加速的 window 后,这个方法只会返回 true,即使在设置了 view.setLayerType(View.LAYER_TYPE_SOFTWARE, null) 之后。如果 view 已经附着到关闭硬件加速的 window 中,则只会返回 false。这种判断方法并不靠谱。

Canvas.isHardwareAccelerated(),如果 Canvas 经过硬件加速,则其会返回 true。在绘制代码中如果要判断 view 是否启用硬件加速时,应该用这个方法而不是上面那个。

ViewLayer

View Layer 又称离屏缓冲,它的作用是单独开辟一块地方来绘制 view,

前面提到 View 不能启用硬件加速,只能停用硬件加速具体展开情况如下:

如果 View 附着的 window 启用硬件加速,则可通过 view.setLayerType(View.LAYER_TYPE_SOFTWARE, null) 关闭(暂停)硬件加速,此后还是可以通过 view.setLayerType(View.LAYER_TYPE_SOFTWARE, null) 或者 view.setLayerType(View.LAYER_TYPE_NONE, null) 来恢复硬件加速的,因为 Window 一开始是支持硬件加速的,故不能说 view 能启动硬件加速。

如果 View 附着 的 window 没有启用硬件加速(Activity 关闭了硬件加速),无论 view 设置 LayerType 为何值,都不能启用硬件加速。

当我们设置了 View Layer 后,绘制操作会被缓存下来,而且缓存的的是最终的绘制结果。这样,View 的重绘效率进一步提升:只要绘制的内容没有变,那么无论是软件绘制(CPU)还是硬件绘制(GPU),它们都不用重新计算,只用之前的缓存的绘制结果即可。(可以对标图片加载缓存来理解。)

硬件加速与动画

动画在 App 中是必不可少的,而动画又是相对消耗性能的,卡顿的动画严重影响用户体验。幸运的是,我们可以通过设置 Hardware Layer 的方式提升动画的效率,代码如下:

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)

ObjectAnimator.ofFloat(view, "rotationY", 180f).apply {

addListener(object : AnimatorListenerAdapter() {

override fun onAnimationEnd(animation: Animator) {

view.setLayerType(View.LAYER_TYPE_NONE, null)

}

})

start()

}

设置 Hardware Layer 会占用视频内存,因此我们应该只在动画播放期间启用。之所以能提高动画效率是因为在进行移动、旋转、缩放、透明度(无需调用 invalidate)的动画时候,View 本身并没有发生改变,只是它的位置或者角度改变了,而这种改变是可以由 GPU 通过简单计算就完成的,并不需要重绘整个 View。与之对应的,如果我们开启的是 自定义属性绘制的动画或者手动调用了 invalidate,这种设置方式是没有用的。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值