Android显示之应用界面绘制
越到上层,跟业务关联越直接。代码就越繁杂。Android上层显示的代码正是如此。此外,java语言本身繁复的特点(比C语言多了满屏的try-catch,比C++少了析构处理的优雅简洁,和更高级的语言scala、python等就别比了),更加剧了这一现象。
直接去看代码,往往会看得一头雾水,知其然而不知其所以然。在这时候,就要把代码扔掉。细致去理清须要实现什么,怎么实现,画一幅架构设计图出来,然后再跟代码去对照。
Android这部分代码并非圣经,有非常多待商榷的地方。心中要有主见,批判性地看。
因为中间各种事耽搁。加上懒。一直没空写长篇博文。间隔了非常长一段时间,请读者先回想显示概述与下层显示:
http://blog.csdn.net/jxt1234and2010/article/details/44164691
另外,因为Android显示还是有不少人写的。某些模块有写得比較好的文章我就直接上链接。不自己写了,见谅。
下层显示关键词:SurfaceFlinger
上层显示关键词:View
初步章节安排:
1、界面绘制
2、布局计算
3、硬件加速下层实现
4、典型控件
5、资源管理
UI引擎设计原则
易用性
一般都会提供足够多的默认控件,但假设应用有更绚丽的效果要求,也会提供接口实现。
高效性
作为UI引擎,掌控着足够完整的渲染流程,优化空间是相当大的。相对而言。难度也更大。
这个高效反映在双方面,一是图形引擎的高效,一是脏区域识别的高效。
图形引擎的高效
第一个重要的点是下层图形引擎的选用
图形引擎的高效反映在两个方面:单体性能和复合性能。单体性能即渲染单个物体的性能,复合性能则是指在多个物体一起渲染的性能(多个物体一起渲染,有一些优化手段。比方作遮挡推断,消除非必要渲染。又比方作区域分划。多线程绘制各区域上的物体)。
图形引擎能够基于CPU渲染,也能够基于GPU渲染。
就一般的UI渲染而言,CPU图形引擎优化得足够,倒也能满足要求,不会比GPU引擎差多少。
识别脏区域
与游戏界面的实时变换不同,对普通应用UI界面的渲染而言。大部分情况下一个页面的大部分面积处于不变状态。变化的区域又称脏区域。如何尽可能多地识别不变的部分,并作渲染规避,是UI引擎须要完毕的非常重要的工作。
比較理想的UI引擎的设计结构例如以下图:
Android没有明白的UI解析引擎,UI解析反映在View、Layout等类的实现中。
应用开发人员使用View的API(UI接口)、Canvas的API(引擎API)进行开发。
View
Android的控件和布局管理都抽象为View。
部分View用于布局解析(各种Layout),部分View用于管理(复合View),部分View是实际的控件(TextView、ImageView、WebView等)。
详细的渲染流程全然取决于应用所选择的View的子类。
全部View组成一个树,布局时逐层创建树节点,渲染时逐级渲染。当调用invalidate刷新View时。由下往上逐层上 dirty区域。
详细可看这篇文章。写得比較清楚:
http://blog.csdn.net/xu_fu/article/details/7829721
一个View不管其渲染流程如何,都必须保证其绘制内容固定在屏幕的指定范围。这是Android上层显示的设计原则。对于使用系统的图形引擎的应用。这能够通过在大图层上划分一块区域,设置裁剪范围而实现。但假设不使用系统图形引擎,就仅仅好新建一个图层,并将主图层相应位置挖洞。
在View的invalidate函数中。将须要重绘的View作标志。
并将其区域与上一级View的脏区域作合并,终于反映到ViewRootImpl的mDirty中来。
invalidate顺着View树脉络,一层一层往上刷新。
渲染流程
软件渲染
drawSoftware
简洁明快的流程:
1、调 surface.lockCanvas,取得渲染入口Canvas。
2、从顶层View開始,按树递归调用View的draw方法。在draw方法中。全部View中的onDraw实现被调用。
3、调 surface.unlockCanvasAndPost
第1步相应的下层逻辑还是有点复杂的:
(1)dequeueBuffer获取一块新GraphicBuffer。
(2)将新GraphicBuffer锁定(lock),指明为CPU所訪问。
(3)优化:假设存在上一帧所渲染的GraphicBuffer,且长宽与当前窗体一致,那么复制上一帧非dirty区域的内容到新一帧。假设不存在。将dirty区域设为全屏(即全部区域都要渲染)。
(4)将GraphicBuffer映射为一个SkBitmap,相应创建一个SkCanvas与之绑定,SkCanvas设置裁剪区域为第(3)步得到的dirty区域。
(5)SkCanvas包装为上层的Canvas传回。
第3步相应的下层逻辑就是 queueBuffer。
请注意,不是仅仅须要绘制dirty的View的,因为View有可能会重叠,发生透明度混合,重叠部分影响到非dirty的View时,也应该绘制。Android并没有计算哪些View须要重绘。就笼统地让全部View运行onDraw方法。
软件渲染流程中,布局、渲染、事件响应全部集中在主线程,比較easy造成堵塞。
硬件渲染
为何要有硬件渲染这套流程。而不是仅改造图形引擎为用gpu的呢
这是因为直接按软件渲染那套流程走下来,是不适合用gpu渲染的,强行换用OpenGL实现,效率会低得可怜。
硬件加速中draw的实如今ThreadedRenderer.java之中(这是5.0的,不同版本 可能有不同,重点看原理)。
1、把创建好的Surface扔给硬件加速的Renderer,供其初始化(eglCreateWindowSurface要用)。
2、更新显示列表(updateRootDisplayList):创建一个记录命令的Canvas,将View中对Canvas的draw操作变成记录命令,非dirty的View不须要又一次记录。
3、运行渲染(nSyncAndDrawFrame)。这一步是放渲染线程里面发一个任务,让其做一次绘制。一般不须要等渲染线程绘制完毕。
详细实如今 DrawTask的drawFrame函数。兴许章节详述:
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
从设计而言,硬件加速的渲染流程要比软件渲染流程好一些。显示列表的存在,给复合优化带来可能。即使不用gpu加速,也都有优势。
关于硬件加速几个常见问题和误区:
1、为何开启硬件加速要额外的内存
非常多文章里面将其误觉得是开启OpenGL所须要的额外内存。事实上不然。OpenGL上下文的内存消耗不会达到MB级,这个额外内存是hwui引擎所须要的缓存。大头是字体。
详细大小能够通过设置系统属性改动。通过 adb shell getprop,可查看相关的属性(ro.hwui开头)。
一般手机上的DDR带宽才800M/s(高端手机应该有1600),这就占用了差点儿1/3。
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览91352 人正在系统学习中 相关资源:按软件服务对象的范围划分-软件工程课件-专业指导文档类资源-CSDN…
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!