数据处理在UI线程
占用CPU高,导致主线程拿不到时间片
内存增加导致GC频繁,从而引起卡顿
#一、Android系统显示原理
Android的显示过程可以简单概括为:Android应用程序把经过测量、布局、绘制后的surface缓存数据、通过SurfaceFlinger把数据渲染到显示屏幕上,通过Android的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕。
1、绘制原理
应用层
在Android的每个View都会经过Measure和Layout来确定当前需要绘制的View所在的大小和位置,然后,再通过Draw绘制到surface上。在Android系统中整体的绘制源码是在ViewRootImpl类的performTraversals()方法,通过这个方法可以看出Measure和Layout都是递归来获取View的大小和位置,并且以深度作为优先级。显然,层级越深,元素越多,耗时就越长。
对于绘制,Android支持两种绘制方式:
软件绘制(CPU)
硬件绘制(GPU)
硬件加速从Android 3.0开始支持,它在UI显示和绘制效率方面远高于软件绘制。但它的局限如下:
耗电:GPU功耗高于CPU。
兼容性:不兼容某些接口和函数。
内存大:使用OpenGL的接口需要占用内存8MB。
系统层
将数据渲染到屏幕上是通过系统级进程中的SurfaceFlinger服务来实现的,它的主要工作流程如下:
1、响应客户端事件,创建Layer与客户端的Surface建立连接。
2、接收客户端数据和属性,修改Layer属性,如尺寸、颜色、透明度等。
3、将创建的Layer内容刷新到屏幕上。
4、维持Layer的序列,并对Layer的最终输出做裁剪计算。
其中,SurfaceFlinger系统进程和应用进程使用了匿名共享内存SharedClient,并且,每一个应用和SurfaceFlinger之间都会创建一个SharedClient,在每个SharedClient中,最多可以创建31个SharedBufferStack,每一个SharedBufferStack对应一个Surface,即一个window。(其中包含了两个(小于4.1版本)或者三个(4.1及以上版本)缓冲区)
因此,从上可知,一个Android应用程序最多可以包含31个窗口。最后,显示的整体流程如下:
1、应用层绘制到缓冲区。
2、SurfaceFlinger把缓冲区数据渲染到屏幕,其中使用了Android匿名共享内存SharedClient缓存需要显示的数据来达到目的。
绘制的过程首先是 CPU准备数据,通过Driver层把数据交给CPU渲染,其中CPU主要负责Measure、Layout、Record、Execute的数据计算工作,GPU负责Rasterization(栅格化)、渲染。因为图形API不允许CPU直接和GPU通信,所以要通过一个图形驱动的中间层来进行连接,在图形驱动里面维护了一个队列,CPU把display list(待显示的数据列表)添加到队列中,GPU从这个队列中取出数据进行绘制,最终才在显示屏上显示出来。
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅画面所需的60FPS。
2、刷新机制
在4.1版本的Project Butter中对Android Display系统进行了重构,引入了三个核心元素:VSYNC(Vertical Synchronization)、Triple Buffer(三级缓冲)、Choreographer。其中作为Project Buffer核心的VSYNC,即垂直同步可认为是一种定时中断。而Choreographer起调度的作用,将绘制工作统一到VSYNC的某个时间点上,使应用的绘制工作有序。
那么,为什么要推出Project Butter呢?
目的是解决刷新不同步的问题。
在Tripe Buffer出现之前,Android的显示系统采用的是双缓冲技术。
为什么要使用双缓冲技术?
在Linux上通常使用 Framebuffer 来做显示输出,当用户进程更新Framebuffer中的数据后,显示驱动会把FrameBuffer中每个像素点的值更新到屏幕,但是如果上一帧数据还没显示完,Framebuffer中的数据又更新了,就会带来残影的问题,用户会觉得有闪烁感,所以采用了双缓冲技术。
双缓冲的含义?
双缓冲意味着要使用两个缓冲区(在上文提及的SharedBufferStack中),其中一个称为Front Buffer,另一个称为Back Buffer。UI总是先在Back Buffer中绘制,然后再和Front Buffer交换,渲染到显示设备中。即只有当另一个buffer的数据准备好后,才会通过io_ctl系统调用来通知显示设备切换Buffer。
当第一帧数据没有及时处理时,为什么CPU不能在第二个16ms处即VSync到来就开始工作呢?
因为只有两个Buffer;所以4.1版本后,出现了第三个缓冲区:Triple Buffer。它利用CPU/GPU的空闲等待时间提前准备好数据,并不一定会使用。
注意
除非必要,大部分情况下只是用到双缓冲。而且,缓冲区并不是越多越好,要做到平衡到最佳效果。
Google做了这么多的优化,为什么实际开发中应用还存在卡顿现象?
因为 VSync 中断处理的线程优先级一定要最高,否则即使接收到VSync中断,不能及时处理,也是徒劳无功。
Choreographer的作用是什么?
当收到VSYNC信号时,调用用户设置的回调函数。回调类型的优先级从高到低为CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL。
3、卡顿的根本原因
绘制任务太重、绘制一帧内容耗时太长。
主线程太忙,导致VSync信号到来时还没有准备好数据从而导致丢帧。
#二、性能分析工具
Android常用的绘制优化工具一般有如下几种:
Hierarchy View:查看Layout层次
Android Studio自带的Profile CPU工具
静态代码检查工具Lint
Profile GPU Rendering
TraceView
Systrace
这里我们来讲解后面三种分析工具。
1、卡顿检测工具Profile GPU Rendering
它是Android手机上自带的一个辅助工具,打开Profile GPU Rendering后可以看到实时刷新的彩色图,其中每一根竖线表示一帧,由多个颜色组成。
Android M之前
在Android M版本之前,每一条柱状图都由红、黄、蓝、紫组成,分别对应每一帧在不同阶段的实际耗时不同颜色的解释如下:
蓝色:表示测量绘制的时间,需要多长时间去创建和更新DisplayList。在蓝色的线很高时,有可能是因为需要重新绘制,或者自定义视图的onDraw函数处理事情太多。
红色:表示Android进行2D渲染Display List的执行的时间。当红色的线非常高时,可能是由于重新提交了视图导致的。
橙色:处理时间或CPU告诉GPU渲染一帧的地方,如果柱状图很高,就意味着GPU太繁忙了。
紫色:将资源转移到渲染线程的时间。(4.0版本以上提供)
Android M及之后
并且,从Android M开始变成了渲染八步骤:
1、橙色-Swap Buffers
表示GPU处理任务的时间。
2、红色-Command Issue
进行2D渲染显示列表的时间,越高表示需要绘制的视图越多。
3、浅蓝-Sync&Upload
准备有待绘制的图片所耗费的时间,越高表示图片数量越多或图片越大。
4、深蓝-Draw
测量和绘制视图所需的时间,越高表示视图越多或onDraw方法有耗时操作。
5、一级绿-Measure/Layout
onMeasure与onLayout所花费的时间。
6、二级绿-Animation
执行动画所需要花费的时间。越高表示使用了非官方动画工具或执行中有读写操作。
7、三级绿-Input Handling
系统处理输入事件所耗费的时间。
8、四级绿-Misc Time/Vsync Delay
主线程执行了太多任务,导致UI渲染跟不上vSync的信号而出现掉帧。
此外,可通过如下 adb命令将具体的渲染耗时输出到日志中来分析:
adb shell dumpsys gfxinfo com..
复制代码
2、TraceView
它主要用来分析函数的调用过程,可以对Android的应用程序以及Framework层代码进行性能分析。
使用TraceView查看耗时,主要关注Calls + Recur Calls / Total和(该方法调用次数+递归次数)和Cpu Time / Call(该方法耗时)这两个值,然后优化这些方法的逻辑和调用次数,减少耗时。
注意
RealTime(实际时长)的实际执行时间要比CPU Time要长,因为它包括了CPU的上下文切换、阻塞、GC等时间消耗。
3、Systrace UI性能分析
Systrace是Android 4.1及以上版本提供的性能数据采样和分析工具,它的主要作用可以归结为如下两点:
1、收集Android关键子系统(如surfaceflinger、WindowManagerService等Framework部分关键模块、服务、View系统等)的运行信息,这样可以更直观地分析系统瓶颈,改进性能。
2、跟踪系统的I/0操作、内核工作队列、CPU负载等,在UI显示性能分析上提供很好的数据,特别是在动画播放不流畅、渲染卡顿等问题上。
1、Systrace使用方法
使用事项如下:
支持4.1版本及以上。
4.3以前的系统版本需要打开Setting>Developer options>Monitoring>Enable traces。
一般我们使用命令行来得到输出的html表单,在4.3版本及以上可以省略设置跟踪类别标签来获取默认值。命令如下:
cd android-sdk/platform-tools/systrace
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
复制代码
其中,常用的几个参数命令如下:
-o :保存的文件名。
-t N, --time=N:多少秒内的数据,默认为5s,以当前时间点往后倒N秒时间。
其余标签用法请参见此处。
此外,我们可以使用代码插桩的方式,在Android 4.3及以上版本可以使用Trace类的Trace.beginSection()与Trace.endSection()方法来进行追踪。其中需要注意:
1、保证beginSection和endSection的调用次数要匹配。
2、Trace的begin与end必须在同一线程中执行。
2、分析Systrace报告
使用Chrome打开文件后,其中和UI绘制关系最密切的是Alerts和Frame两个数据:
Alerts:标记了性能有问题的点,单击该点可以查看详细信息,右侧的Alerts框还可以看到每个类型的Alerts的数量。
Frame:每个应用都有一行专门显示frame,绘制正常时每一帧就显示为一个绿色的圆圈。当显示为黄色或者红色时,则表明它的渲染时间超过了16.6ms。
最后,这里再列出在Systrace便于操作的快捷键:
W:放大
S:缩小
A:左移
D:右移
#三、布局优化方式
1、减少层级
合理使用RelativeLayout和LinearLayout。
合理使用Merge。
合理使用RelativeLayout和LinearLayout
RelativeLayout也存在性能低的问题,原因是RelativeLayout会对子View做两次测量。但如果在LinearLayout中有weight属性,也需要进行两次测量,但是因为没有更多的依赖关系,所以仍然会比RelativeLayout的效率高。
注意
由于Android的碎片化程度很高,所以使用RelativeLayout能使构建的布局适应性更强。
合理使用Merge
merge的原理:在Android布局的源码中,如果是Merge标签,那么直接将其中的子元素添加到Merge标签Parent中。
注意
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
面试复习路线,梳理知识,提升储备
自己的知识准备得怎么样,这直接决定了你能否顺利通过一面和二面,所以在面试前来一个知识梳理,看需不需要提升自己的知识储备是很有必要的。
关于知识梳理,这里再分享一下我面试这段时间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)
资料获取方式:前往我的GitHub
- 架构师筑基必备技能
- Android高级UI与FrameWork源码
- 360°全方面性能调优
- 解读开源框架设计思想
- NDK模块开发
- 微信小程序
- Hybrid 开发与Flutter
知识梳理完之后,就需要进行查漏补缺,所以针对这些知识点,我手头上也准备了不少的电子书和笔记,这些笔记将各个知识点进行了完美的总结:
《960全网最全Android开发笔记》
《379页Android开发面试宝典》
历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
[外链图片转存中…(img-eIQj1NXO-1710823207113)]
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。