Android 绘制知识点总结
Android绘制流程
-
绘制前世今生
我们都知道,当一个
Activity
调用setContenView
之后,我们就可以看到我们的内容被展示出来,那么到底是谁,将我们的页面内容,转变成屏幕显示的像素数据呢,我们从来一步步分析
-
DecorView
是我们应用窗口的一个根容器,SetContentView
,其实就是将内容防止到DecorView
的子元素id
为ContentView
的容器中 -
Window
窗口,每一个窗口有一个和它关联的Surface
,窗口的Surface
由WMS
分配,画在表面上的内容并不会马上显示在屏幕上,绘制完成之后,SurfaceFlinger
将多块Surface
按照顺序(Z-order
)进行混合,输出到FrameBuff
,显示到界面SurfaceView
就是有一个单独Surface
-
Window
具体实现为PhoneWindow
,和Activity
唯一对应,PhoneWindow
中持有DecorView
,Activity.setContentView
的操作就是通过PhoneWindow来完成
Activity
,Window
,View
的三者关系,Activity
工匠,Window
窗户,View
窗花 -
ViewRoot
,实现类ViewRootImple
,会在ActivityThread.handleResumeActivity()
和DecorView
进行关联,而后会调用requestLayout
发起绘制 -
绘制的起点,
ViewRootImpl.requestLayout ->scheduleTraversals() -> performTraversals()
-
measure
-> 计算出每个控件需要占据的尺寸-
MeasureSpec
,32
整数,SpecMode
高2
位+SpecSize
剩余30
位,- 测量模式
-
EXACTLY
精准模式,指定了具体的尺寸,如12dp
,或者是match_parent
-
AT_MOST
,最大模式,不得超过SpecSize
-
UNSPECIFIED
,未定义,不做限制,类似ListView
这种系统内部控件
-
- 测量模式
-
-
layout
->计算出每个控件的绘制位置 -
draw
-> 每个空间的具体绘制内容
-
-
绘制核心
SurfaceFlinger
-
无论是
OpenGL ES
还是Canvas
,获取MediaPlayer
等生产者产生的图像数据都会输出到Surface
, -
Surface
也是作为SurfaceFlinger
的生产者,将GraphicBuffer
通过IPC
传到SurfaceFlinger
, -
最终
SurfaceFlinger
根据WMS
提供的窗口信息,合成所有的Layer
(
Layer
和Surface相关联,Surface
是Layer
的屏幕内存的直接表现)
- 图形绘制,不同的方式,都是输出到
Surface
-
Canvas
-
Sika
软件绘制 -
hwui
硬件加速绘制
-
OpenGL ES
-
-
BufferQueue
,在之前的生产者-消费者模式中,所有的数据传输都是通过BufferQueue
-
Canvas/OpenGLES
请求一块空闲的缓存区填充图像数据dequeueBuffer()
,然后将数据返回给队列:queueBuffer()
-
SurfaceFlinger
合成所有图层数据,放到输出缓存区 -
Display
显示控制器 获取合成结果acquireBuffer()
,使用完毕,则返回给队列:releaseBuffer()
-
-
-
双缓冲
CPU
计算好显示内容之后,GPU
负责渲染到FrameBuffer
帧缓冲,然后按照VSync
信用从帧缓冲中取出数据显示到屏幕上,如果只有一块缓冲区,那么数据的更新可能就是表现为逐行的刷新,为了刷新是整帧的,需要双缓冲,刷新时进行直接替换
Android硬件加速
在
Android
中,硬件加速,就是将View
的绘制工作交给GPU
来完成,Android4.0
以后,硬件加速都是默认开启的
Android
硬件加速踩坑
-
一些
Android 4.0
的低端机型,出现花屏,黑色像素,错位等现象,错误日志OpenGLRender:0x510
-
针对一些自定义的复杂的
View
,可能会存在渲染异常,出现这种情况,可以优先考虑关闭硬件加速-
Application
级别关闭,慎用,这可能会让你整个应用的渲染性能下降<application android:hardwareAccelerated="false">
-
Activity
级别关闭,悠着点,影响也不小<activity android:hardwareAccelerated="false">
-
Window
级别,悠着点,也是和Activity
类似getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-
View
级别,这个比较推荐!!view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);//指定为软件渲染 //也可以在布局文件xml中 android:layerType="software"
-
-
-
针对一些绘制相关的操作,也有一些
api
是在特定版本后才开始支持硬件加速的
-
Api
支持版本 canvas.clipRegion()
18 canvas.clipPath()
18
-
网友评论