深入Android渲染机制

简介: 1.知识储备CPU: 中央处理器,它集成了运算,缓冲,控制等单元,包括绘图功能.CPU将对象处理为多维图形,纹理(Bitmaps、Drawables等都是一起打包到统一的纹理).GPU:一个类似于CPU的专门用来处理Graphics的处理器, 作用用来帮助加快栅格化操作,当然,也有相应的缓存数据(例如缓存已经光栅化过的bitmap等)机制。

1.知识储备

  • CPU: 中央处理器,它集成了运算,缓冲,控制等单元,包括绘图功能.CPU将对象处理为多维图形,纹理(Bitmaps、Drawables等都是一起打包到统一的纹理).

  • GPU:一个类似于CPU的专门用来处理Graphics的处理器, 作用用来帮助加快栅格化操作,当然,也有相应的缓存数据(例如缓存已经光栅化过的bitmap等)机制。

  • OpenGL ES是手持嵌入式设备的3DAPI,跨平台的、功能完善的2D和3D图形应用程序接口API,有一套固定渲染管线流程. 附相关OpenGL渲染流程资料

  • DisplayList 在Android把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。

  • 栅格化 是 将图片等矢量资源,转化为一格格像素点的像素图,显示到屏幕上,过程图如下.

img_bedb07d9d5714f1ddfc5b74d794c041b.png
栅格化操作
  • 垂直同步VSYNC:让显卡的运算和显示器刷新率一致以稳定输出的画面质量。它告知GPU在载入新帧之前,要等待屏幕绘制完成前一帧。下面的三张图分别是GPU和硬件同步所发生的情况,Refresh Rate:屏幕一秒内刷新屏幕的次数,由硬件决定,例如60Hz.而Frame Rate:GPU一秒绘制操作的帧数,单位是30fps,正常情况过程图如下.
img_a86d70e1b60fe353c3d2973542a36360.png
正常情况

2.渲染机制分析

渲染流程线

UI对象---->CPU处理为多维图形,纹理 -----通过OpeGL ES接口调用GPU----> GPU对图进行光栅化(Frame Rate ) ---->硬件时钟(Refresh Rate)----垂直同步---->投射到屏幕

img_94682addd84c3d58d365f9c4db0d8b1f.png
图片名称

渲染时间线

Android系统每隔16ms发出VSYNC信号(1000ms/60=16.66ms),触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着计算渲染的大多数操作都必须在16ms内完成。

正常情况

img_5fc2375f63c9543e4c54d163e4a9d37f.png
这里写图片描述

渲染超时,计算渲染时间超过16ms

当这一帧画面渲染时间超过16ms的时候,垂直同步机制会让显示器硬件 等待GPU完成栅格化渲染操作,
这样会让这一帧画面,多停留了16ms,甚至更多.这样就这造成了 用户看起来 画面停顿.

img_fbc3057eff745aadc3f40618ef385d98.png

当GPU渲染速度过慢,就会导致如下情况,某些帧显示的画面内容就会与上一帧的画面相同

img_e5953d67117044a725c60df0d259b4ca.png
GPU超时情况

3.渲染时会出现的问题

GPU过度绘制

GPU的绘制过程,就跟刷墙一样,一层层的进行,16ms刷一次.这样就会造成,图层覆盖的现象,即无用的图层还被绘制在底层,造成不必要的浪费.

img_80d9e2cb6444b1642f7924d94fa12385.png
这里写图片描述

过度绘制查看工具

在手机端的开发者选项里,有OverDraw监测工具,调试GPU过度绘制工具,
其中颜色代表渲染的图层情况,分别代表1层,2层,3层,4层覆盖.

img_d8255838e654a712492dc97d53362a7c.png
这里写图片描述

我的魅族手机的Monitor GPU Rendering

img_e3801c21525141d9708ad99398a7bcc5.png
这里写图片描述

计算渲染的耗时

任何时候View中的绘制内容发生变化时,都会重新执行创建DisplayList,渲染DisplayList,更新到屏幕上等一 系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。

举个例子,当View的大小发生改变,DisplayList就会重新创建,然后再渲染,而当View发生位移,则DisplayList不会重新创建,而是执行重新渲染的操作.

当你的View过于复杂,操作又过于复杂,就会计算渲染时间超过16ms,产生卡顿问题.

img_20598ec3d0647661510d77674d789f19.png

渲染耗时呈现工具

工具中,不同手机呈现方式可能会有差别.分别关于StatusBar,NavBar,激活的程序Activity区域的GPU Rending信息。激活的程序Activity区域的GPU Rending信息。

界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。

中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。

img_3e0ce42f3e59a8ba6987d5adb7782f72.jpe
这里写图片描述

每一条柱状线都包含三部分,
蓝色代表测量绘制Display List的时间,
红色代表OpenGL渲染Display List所需要的时间,
黄色代表CPU等待GPU处理的时间。

img_ae95054a1fc7d914c6974516326f7696.png
这里写图片描述

4.如何优化

有人会说这些小地方,不值得优化.但是当你用的是低配机器,内存到饱和,CPU运算到达饱和,就像一个界面要做很多交互,绘制,加载图片,请求网络.后,一个小问题就会导致页面卡顿(就像我手机的淘宝客户端...),OOM,项目崩溃.

是的,这就是力量~

Android系统已经对它优化

在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到 GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。

我们要做的优化

扁平化处理,防止过度绘制OverDraw

**1.每一个layout的最外层父容器 是否需要? **

img_ee8068796fc9eca0b7858ca23c289181.png
这里写图片描述

**2.布局层级优化 **

进行检测时,可能会让多种检测工具冲突,用Android Device Monitor的时候,最好关闭相关手机上的开发者检测工具开关.
查看自己的布局,深的层级,是否可以做优化.
渲染比较耗时(颜色就能看出来),想办法能否减少层级以及优化每一个View的渲染时间.

Hierarchy Viewer工具

他是查看耗时情况,和布局树的深度的工具.

img_20fffd1b4b2b421e59ff8ced53f94ea2.png
这里写图片描述

3.图片选择

Android的界面能用png最好是用png了,因为32位的png颜色过渡平滑且支持透明。jpg是像素化压缩过的图片,质量已经下降了,再拿来做9path的按钮和平铺拉伸的控件必然惨不忍睹,要尽量避免。

对于颜色繁杂的,照片墙纸之类的图片(应用的启动画面喜欢搞这种),那用jpg是最好不过了,这种图片压缩前压缩后肉眼分辨几乎不计,如果保存成png体积将是jpg的几倍甚至几十倍,严重浪费体积。

4.清理不必要的背景

img_039f279cb77b421fed324246fe0933e4.png
这里写图片描述

5.当背景无法避免,尽量用Color.TRANSPARENT

因为透明色Color.TRANSPARENT是不会被渲染的,他是透明的.


//优化前
//优化前: 当图片不为空,ImageView加载图片,然后统一设置背景
Bean bean=list.get(i);
 if (bean.img == 0) {
            Picasso.with(getContext()).load(bean.img).into(holder.imageView);
        }
        chat_author_avatar.setBackgroundColor(bean.backPic);

//优化后
//优化后:当图片不为空,ImageView加载图片,并设置背景为TRANSPARENT;
//当图片为空,ImageView加载TRANSPARENT,然后设置背景为无照片背景
Bean bean=list.get(i);
 if (bean.img == 0) {
            Picasso.with(getContext()).load(android.R.color.transparent).into(holder.imageView);
            holder.imageView.setBackgroundColor(bean.backPic);
        } else {
            Picasso.with(getContext()).load(bean.img).into(holder.imageView);
            holder.imageView.setBackgroundColor(Color.TRANSPARENT);
        }

-------------对比结果--------------------


img_dbd46811cbdc07a1e1d6afb4ab26f2e4.png
这里写图片描述

6.优化自定义View的计算

View中的方法OnMeasure,OnLayout,OnDraw.在我们自定义View起到了决定作用,我们要学会研究其中的优化方法.

学会裁剪掉View的覆盖部分,增加cpu的计算量,来优化GPU的渲染


  /**
     * Intersect the current clip with the specified rectangle, which is
     * expressed in local coordinates.
     *
     * @param left   The left side of the rectangle to intersect with the
     *               current clip
     * @param top    The top of the rectangle to intersect with the current clip
     * @param right  The right side of the rectangle to intersect with the
     *               current clip
     * @param bottom The bottom of the rectangle to intersect with the current
     *               clip
     * @return       true if the resulting clip is non-empty
     */
    public boolean clipRect(float left, float top, float right, float bottom) {
        return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom,
                Region.Op.INTERSECT.nativeInt);
    }


5.总结

性能优化其实不仅仅是一种技术,而是一种思想,你只听过它的高大上,却不知道它其实就是各个细节处的深入研究和处理.

当然,有的时候也需要自己进行权衡效果和性能,根据需求进行选择.

还有,Android Device Monitor 是个好东西~简直就是性能优化大本营,性能优化的工具基本都在其中.

所以在平时的开发过程中,养成良好的思考习惯,是第一步~

写代码的时候要想:

1.你的代码是不是多余?

2.你的对象有没有必要在循环中创建?

3.你的计算方法是不是最优?

画界面的时候要想:

1.布局是否有背景?

2.是否可以删掉多余的布局?

3.自定义View是否进行了裁剪处理?

4.布局是否扁平化,移除非必需的UI组?

最后,Android Device Monitor 是个好东西~ 性能优化的工具基本都在其中.

关于我:

我的github: https://github.com/ccj659/

我的简书: 简书地址传送门

我的CSDN博客: http://blog.csdn.net/ccj659/article

我的上一篇性能优化文章: 深入android内存泄漏

QQ进阶交流群:570381965

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
17天前
|
消息中间件 网络协议 Java
Android 开发中实现数据传递:广播和Handler
Android 开发中实现数据传递:广播和Handler
16 1
|
19天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
20天前
|
Unix Linux Shell
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
在Linux环境下交叉编译Android所需的FFmpeg so库,首先下载`android-ndk-r21e`,然后解压。接着,上传FFmpeg及相关库(如x264、freetype、lame)源码,修改相关sh文件,将`SYSTEM=windows-x86_64`改为`SYSTEM=linux-x86_64`并删除回车符。对x264的configure文件进行修改,然后编译x264。同样编译其他第三方库。设置环境变量`PKG_CONFIG_PATH`,最后在FFmpeg源码目录执行配置、编译和安装命令,生成的so文件复制到App工程指定目录。
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
|
7天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
10天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
11天前
|
监控 Java Android开发
安卓应用开发:打造高效用户界面的五大策略
【4月更文挑战第29天】 在安卓应用开发的世界中,构建一个既美观又高效的用户界面(UI)对于吸引和保留用户至关重要。本文将深入探讨五种策略,这些策略可以帮助开发者优化安卓应用的UI性能。我们将从布局优化讲起,逐步过渡到绘制优化、内存管理、异步处理以及最终的用户交互细节调整。通过这些实践技巧,你将能够为用户提供流畅而直观的体验,确保你的应用在竞争激烈的市场中脱颖而出。
|
2天前
|
Java API 开发工具
java与Android开发入门指南
java与Android开发入门指南
8 0
|
3天前
|
Android开发 Kotlin
Kotlin开发Android之基础问题记录
Kotlin开发Android之基础问题记录
15 1
|
3天前
|
Java Android开发
Android开发@IntDef完美替代Enum
Android开发@IntDef完美替代Enum
12 0
|
4天前
|
Android开发
Android 盒子开发过程中遇到的问题及解决方法
Android 盒子开发过程中遇到的问题及解决方法
8 2