Android 渲染机制——绘制模型

Android 绘制模型


由于 CPU 和 GPU 的设计不同,CPU 更擅长复杂逻辑控制,而 GPU 得益于大量 ALU 和并行结构设计,更擅长数学运算。在 Android 中,页面由各种基础元素(DisplayList)构成,渲染时需要进行大量浮点运算,这些工作更适合交给 GPU 来做。Android 为了提高视图渲染的性能,在 Android 3.0 中引入了硬件加速。这样 Android 中就存在了2种绘制模型了。

Android 有两种绘制模型:

  • 基于软件的绘制模型
  • 硬件加速绘制模型

在这里插入图片描述

基于软件的绘制模型

Android 早期版本,默认使用的就是基于软件的绘制模型,在使用硬件加速之后,改为了硬件加速绘制模型,以提高渲染性能。

在软件绘制模型中,绘制视图分为以下两步:

  1. 对层次结构进行无效化处理
  2. 绘制层次结构

每当应用当前显示的界面上的一部分组件需要更新时,就会对内容已发生更改的所有视图调用 invalidate()(或其变体之一),可以理解为“无效化”。“无效化”消息会一直传播到视图层次结构上层,以计算需要重新绘制的屏幕区域(脏区域)。然后,Android 系统会绘制层次结构中与脏区域交互的所有视图。

该绘制模式是在 Android 启用硬件加速之前使用的模式,它有以下两个缺点:

  1. 每次绘制时该模型都需要执行大量代码。例如,如果在应用中对某个按钮调用 invalidate() 且该按钮位于另一个视图上方,那么即使该视图未发生更改,Android 系统仍会重新绘制该视图,这样就会造成性能上的浪费。
  2. 该绘制模型会隐藏应用中的错误。上面已经介绍, Android 系统会在视图与脏区域交互时重新绘制视图,假如我们有一个视图组件做了属性改变,但是它没有调用 invalidate(),也就是不想进行刷新,但是如果它在脏区域中,就会被重新绘制,这不是我们想要的结果。如果发生这种情况,我们要依赖其他经过无效化处理的视图才能获得正确的行为。每次修改应用时,此行为都可能会发生更改。因此,每次修改会影响视图绘制代码的数据或状态后,都要对自定义视图调用 invalidate()。

我们在开发时,好像遇到调用 invalidate() 方法的情景较少(通常都是自定义视图组件中),这是因为 Android 视图(View 组件)会在其属性(例如 TextView 中的背景颜色或文本)发生更改时自动调用 invalidate()。

硬件加速绘制模型

从 Android 3.0(API 级别 11)开始,Android 2D 渲染管道支持硬件加速,也就是说,在 View 的画布上执行的所有绘制操作都会使用 GPU。在目标 API 级别为 14 及更高级别(Android 4.0+),则硬件加速默认处于启用状态。这时,Android 使用的绘制模型就转变为硬件加速绘制模型了。

在硬件加速绘制模型中,Android 系统仍会使用 invalidate() 和 draw() 请求屏幕更新和渲染视图,但会采用其他方式处理实际绘制过程。Android 系统不会立即执行绘制命令,而是将这些命令记录在显示列表中(Display List),这些列表中包含视图层次结构绘制代码的输出。另一项优化是,Android 系统只需要记录和更新被 invalidate() 调用标记为脏视图的视图的显示列表。只需重新发出之前记录的显示列表,即可重新绘制未经过无效化处理的视图。这其实相当于增加了一层内存缓存,对不需要改变的视图提高了处理效率。

新绘制模型包含以下三个阶段:

  1. 对层次结构进行无效化处理
  2. 记录并更新显示列表
  3. 绘制显示列表

使用此模型时,系统避免了视图与脏区域交互时的重新绘制,这样如果我们要确保 Android 系统会记录某个视图的显示列表,该视图就必须调用 invalidate() 方法。

使用显示列表还有助于改进动画性能,因为设置特定属性(例如 Alpha 或旋转)不需要对目标视图进行无效化处理(该操作是自动完成的)。这项优化还适用于具有显示列表的视图(如果应用经过硬件加速,则适用于所有视图)。

当然,使用硬件加速功能,也存在一些缺点:兼容性(API 不同版本有所不同)、内存消耗和电量消耗(GPU 耗电)。

硬件加速绘制模型的一个示例

理论知识我们已经了解,接下来看一个具体实例。

假设有一个 LinearLayout,其中包含一个 ListView(位于 Button 之上)。LinearLayout 的显示列表如下所示:

  • DrawDisplayList(ListView)
  • DrawDisplayList(Button)

现在,假设我们要更改 ListView 的不透明度。在对 ListView 调用 setAlpha(0.5f) 后,显示列表现在包含以下内容:

  • SaveLayerAlpha(0.5)
  • DrawDisplayList(ListView)
  • Restore
  • DrawDisplayList(Button)

系统没有执行 ListView 的复杂绘制代码,而是仅更新了更为简单的 LinearLayout 的显示列表。这就相比在未启用硬件加速的应用中,系统会再次执行列表及其父级的绘制代码,大大提高了性能。

总结


  1. Android 为了提高视图渲染的性能,在 Android 3.0 中引入了硬件加速。

  2. Android 有两种绘制模型:基于软件的绘制模型、硬件加速绘制模型。

  3. Android 早期版本,默认使用的就是基于软件的绘制模型。从 Android 3.0(API 级别 11)开始,Android 2D 渲染管道支持硬件加速,也就是说,在 View 的画布上执行的所有绘制操作都会使用 GPU。在目标 API 级别为 14 及更高级别(Android 4.0+),则硬件加速默认处于启用状态。这时,Android 使用的绘制模型就转变为硬件加速绘制模型了。

  4. 使用硬件加速绘制模型,系统避免了视图与脏区域交互时的重新绘制,这样如果我们要确保 Android 系统会记录某个视图的显示列表,该视图就必须调用 invalidate() 方法。


**PS:更多精彩内容,请查看 --> 《Android 性能优化》
**PS:更多精彩内容,请查看 --> 《Android 性能优化》
**PS:更多精彩内容,请查看 --> 《Android 性能优化》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卜大爷

觉得不错的可以给我加油哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值