Android 绘制原理

一、概括

Android 的显示过程可以简单概括为:Android 应用程序把经过测量、布局、绘制后的surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上,通过 Android 的刷新机制 来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要 绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕。 通过阅读 Android 系统的源码可以了解显示的流程,Android 的图形显示系统采用的是 Client/Server 架构。SurfaceFlinger(Server)由 C++代码编写。Client 端代码分为两部分,一 部分是由 Java 提供给应用使用的 API,另一部分则是由 C++写成的底层具体实现。

二、绘制原理

绘制任务是由应用发起的,最终通过系统层绘制到硬件屏幕上,也就是说,应用进程绘 制好后,通过跨进程通信机制把需要显示的数据传到系统层,由系统层中的 SurfaceFlinger 服务绘制到屏幕上。那么应用层和系统层中的流程是什么样的呢?

1、应用层

  • 先来看一个 UI 界面的典型构成框架,也可以是一个 Activity 的构成。如图 2-2 所示,有 很多不同层次的基本元素——View,整体是一个树型结构,有不同的嵌套,存在着父子关系, 子 View 在父 View 中,这些 View 都经过一个相同的流程最终显示到屏幕上,这也意味着要 完整地显示所有数据,就要对其中的 View 都进行一次绘制工作,并且针对每个 View 的操作 都是一个递归过程。
  • 在 Android 的每个 View 绘制中有三个核心步骤(见图 2-3),通过 Measure 和 Layout 来 确定当前需要绘制的 View 所在的大小和位置,通过绘制(Draw)到 surface,在 Android 系 统中整体的绘图源码是在 ViewRootImp 类的 performTraversals()方法,通过这个方法可以 看出 Measure 和 Layout 都是递归来获取 View 的大小和位置,并且以深度作为优先级。可以 看出,层级越深,元素越多,耗时也就越长。

(1)Measure 用深度优先原则递归得到所有视图(View)的宽、高;获取当前 View 的正确宽度 childWidthMeasureSpec 和高度 childHeightMeasureSpec 之后,可以调用它的成员函数 Measure 来设置它的大小。如果当前正在测量的子视图 child 是一个视图容器,那么它又会 重复执行操作,直到它的所有子孙视图的大小都测量完成为止。

(2)Layout 用深度优先原则递归得到所有视图(View)的位置;当一个子 View 在应用程序窗口左 上角的位置确定之后,再结合它在前面测量过程中确定的宽度和高度,就可以完全确定它在 应用程序窗口中的布局。

(3)Draw 目前 Android 支持了两种绘制方式:软件绘制(CPU)和硬件加速(GPU),其中硬件加 速在 Android 3.0 开始已经全面支持,很明显,硬件加速在 UI 的显示和绘制的效率远远高于 CPU 绘制,但硬件加速并非如大家所想的那么完善,它也存在明显的缺点: ·耗电:GPU 的功耗比 CPU 高。 ·兼容问题:某些接口和函数不支持硬件加速。 ·内存大:使用 OpenGL 的接口至少需要 8MB 内存。 所以是否使用硬件加速,需要考虑一些接口是否支持硬件加速,同时结合产品的形态和 平台,比如 TV 版本就不需要考虑功耗的问题,而且 TV 屏幕大,使用硬件加速容易实现更 好的显示效果。

2、系统层

真正把需要显示的数据渲染到屏幕上,是通过系统级进程中的 SurfaceFlinger 服务来实 现的,SurfaceFlinger 的主要工作如下:

  • 响应客户端事件,创建 Layer 与客户端的 Surface 建立连接。
  • 接收客户端数据及属性,修改 Layer 属性,如尺寸、颜色、透明度等。
  • 将创建的 Layer 内容刷新到屏幕上。
  • 维持 Layer 的序列,并对 Layer 最终输出做出裁剪计算

既然是两个不同进程,那么肯定需要一个跨进程的通信机制来实现数据传输,在 Android 的显示系统,使用了 Android 的匿名共享内存:SharedClient,每一个应用和 SurfaceFlinger 之间都会创建一个 SharedClient,如下图所示。从图中可以看出,在每个 SharedClient 中,最多可以创建 31 个 SharedBufferStack,每个 Surface 都对应一个 SharedBufferStack,也 就是一个 window。 一个 SharedClient 对应一个 Android 应用程序,而一个 Android 应用程序可能包含多个窗 口,即 Surface。也就是说 SharedClient 包含的是 SharedBufferStack 的集合。因为最多可以创 建 31 个 SharedBufferStack,这也意味着一个 Android 应用程序最多可以包含 31 个窗口,同 时每个 SharedBufferStack 中又包含了两个(低于 4.1 版本)或者三个(4.1 及以上版本)缓 冲区,刷新机制中的双缓冲和三重缓冲技术。
在这里插入图片描述
最后总结起来显示整体流程分为三个模块:应用层绘制到缓存区,SurfaceFlinger 把缓存 区数据渲染到屏幕,由于是两个不同的进程,所以使用 Android 的匿名共享内存 SharedClient 缓存需要显示的数据来达到目的。 SurfaceFlinger 把缓存区数据渲染到屏幕(流程如下图所示),主要是驱动层的事情,这 里不做太多解释。

从图中可以看出,绘制过程首先是 CPU 准备数据,通过 Driver 层把数据交给 CPU 渲 染,其中 CPU 主要负责 Measure、Layout、Record、Execute 的数据计算工作,GPU 负责 Rasterization(栅格化)、渲染。由于图形 API 不允许 CPU 直接与 GPU 通信,而是通过中间 的一个图形驱动层(Graphics Driver)来连接这两部分。图形驱动维护了一个队列,CPU 把 display list 添加到队列中,GPU 从这个队列取出数据进行绘制,最终才在显示屏上显示出来。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

互联网小熊猫

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值