android 布局

android 布局详解
原文:http://djt.qq.com/article/view/987

         http://blog.csdn.net/Luoshengyang/article/details/7867340
最近写android的布局,写着写着感觉少了一些东西,所以就查资料将少的东西补上。
Activity:


android的显示(物理屏幕)原理:
SurfaceFlinger(位于android基本框架的第三层(c++)):把系统中所用应用程序的绘图结果的混合通过调用Linux内核驱动再调用硬件绘制在物理屏幕上。
android 应用程序与SurfaceFlinger服务位于不同的进程之中,进程之间的通信机制是builder机制。每个android应用程序与SurfaceFlinger服务都有一个连接,这个连接是android应用程序与SurfaceFlinger服务建立连接时由SurfaceFlinger服务创建的一个clicent builder对象,即远程服务的代理,android应用程序可以通过这个代理通知SurfaceFlinger服务来绘制自己的界面到物理屏幕上。应用程序在通知SurfaceFlinger服务来绘制时需要将ui元数据传递过去,如位置信息、绘制区域等(这些元数据由onmeasure()和ondraw()所提供,经过测量,布局),android应用程序的每一个窗口都有自己的元数据,通过builder机制传递不合适,需要用到匿名内存共享机制(Anonymous Shared Memory),但需要结构化,匿名内存共享机构化后变成SharedClient(即匿名共享内存块),每一个内存块里至多有31个SharedBufferStack(即共享缓冲区堆栈,描述ui的元数据都放在这个堆栈里,由此缓冲区描述,访问这个缓冲区需要遵循一定的访问规则),这个堆栈由android应用程序和SurfaceFlinger共享。SurfaceFlinger服务中,每一个SharedClient内的一个SharedBufferStack都代表一个Surface(窗口),每一个shareClient代表一个应用程序,一个应用程序有很多窗口,但一个sharclient里至多有31个sharebufferstack,所以每一个应用程序至多有31个surface(窗口)。在绘制UI时一般都采用双缓冲的技术,双缓冲意味着要使用2个缓冲区,一个称为Front Buffer,另一个称为Back Buffer,UI在Back Buffer里绘制,再与Front Buffer交换,然后渲染到物理屏幕上。SharedBufferStack时此缓冲技术的升华,有了SharedBufferStack(内含N(3-16)个缓冲区),SurfaceFlinger服务就可以有N(3-16)个缓冲区来绘制UI。SharedBufferStack的缓冲区只是用来描述UI元数据的,而真正存放这些UI元数据的是GraphicBuffer,所以SharedBufferStack中的每一个缓冲区都对应一个GraphicBuffer;当SurfaceFlinger服务缓制Buffer-1和Buffer-2的时候,就会找到与它们所对应的GraphicBuffer,这样就可以将对应的UI绘制出来了。
当android应用程序需要更新一个UI窗口时,它就会在SharedClient(即匿名共享内存的升级版)找到这个窗口所对应的SharedBufferStack,然后从这个SharedBufferStack的空缓冲区列表里取出一个Buffer(假设编号为index),然后请求(bulider通信机制)SurfaceFlinger服务为这个编号为index的buffer分配一个GraphicBuffer,分配好以后,将它的编号设为index,然后SurfaceFlinger服务再将这个编号为index的图形缓存区GraphicBuffer返回给android应用程序访问,android应用程序取得此图形缓存区访问权后,将UI元数据写入此缓存区内。写完以后,就会将它所对应的缓冲区(即编号为index的buffer)插入到SharedBufferStack已用缓冲区列表的头部,完成之后,Android应用程序就通知SurfaceFlinger服务去绘制那些保存在已经使用了的缓冲区所描述的对应其中的图形缓冲区GraphicBuffer了,SurfaceFlinger服务会调用到内核的设备驱动,然后驱动硬件去绘制,这样就显示在物理屏幕上啦。当一个被使用了的buffer绘制完以后,就会变成空闲。
SharedClient(匿名共享内存块)里的SharedBufferStack(共享内存缓冲区堆栈)时android应用程序和SurfaceFlinger服务所共享的,但是两者使用它的方式是不同的,具体来说,就是Android应用程序关心的是它里面的空闲缓冲区列表,而SurfaceFlinger服务关心的是它里面的已经使用了的缓冲区列表。从SurfaceFlinger服务的角度来看,保存在SharedBufferStack中的已经使用了的缓冲区其实就是在排队等待渲染。
为了方便SharedBufferStack在Android应用程序和SurfaceFlinger服务中的访问,Android系统分别使用SharedBufferClient和SharedBufferServer来描述SharedBufferStack,其中,SharedBufferClient用来在Android应用程序这一侧访问SharedBufferStack的空闲缓冲区列表,而SharedBufferServer用来在SurfaceFlinger服务这一侧访问SharedBufferStack的排队缓冲区列表。
---------------------------------------------------------------------
总结:1、android应用程序和SurfaceFlinger服务分别属于不同的进程,通信采用bulider机制。
2、android应用程序UI窗口通过SurfaceFlinger服务(框架第三层 c++)调用HAL硬件层驱动程序(内核中),然后驱动程序驱动硬件根据android应用程序UI元数据将UI窗口界面绘制在物理屏幕上。
3、每一个surface窗口对应一个SharedBufferStack,一个SharedClient里至多有31个SharedBufferStack,也就是说一个android应用程序至多有31个窗口,SharedBufferStack里有N(3-16)个缓冲区buffer,每个缓冲区都会由SurfaceFlinger服务分配对应的图形缓冲区(GraphicBuffer),SharedBufferStack是在Android应用程序和SurfaceFlinger服务之间共享的。


4、Android应用程序的显示过程包含了两个部分(应用侧绘制、系统侧渲染)、两个机制(进程间通讯机制、显示刷新机制)。


绘制过程(当android应用程序需要更新一个surface(窗口)时)
测量:递归(深度优先)确定所有视图的大小(高、宽)
布局:递归(深度优先)确定所有视图的位置(左上角坐标)
应用侧绘制(这个绘制工作会在图形缓冲区内进行,在canvas上绘制View的结构层次(根据前面测量和布局得到的参数),即写入ui元数据到图形缓冲区,图形缓存区在画布中)
[1]android应用程序到SharedClient(匿名共享内存块)找到这个窗口对应的SharedBufferStack(共享缓冲区堆栈)。
[2]找到后从SharedBufferStack的空缓冲区列表的尾部取出一个空闲的缓冲区buffer(假设编号为index)。
[3]取出后,android应用程序通知SurfaceFlinger服务为这个空闲的缓冲区分配一个图形缓冲区(GraphicBuffer),
[4]分配好以后,SurfaceFlinger服务会将这个GraphicBuffer编号为index,
然后将这个GraphicBuffer返回给android应用程序访问。
[5]Android应用程序得到了SurfaceFlinger服务返回的图形缓冲区GraphicBuffer访问权之后,就向里写入UI元数据(即绘制View的层次结构)。
以下就是系统侧渲染过程
[6]写完之后,就将与它所对应的缓冲区,即编号为index的Buffer,插入到对应的SharedBufferStack的已经使用了的缓冲区列表的头部去。
[7]然后Android应用程序就通知SurfaceFlinger服务调用其他api去绘制那些保存在已经使用了的缓冲区所描述的图形缓冲区GraphicBuffer,······最后根据UI元数据绘制在屏幕的指定位置,指定大小,渲染每一个UI元素到surface,最后到物理屏幕上去。
[8]绘制完以后,buffer重新变为空闲。
如果用户直接在Canvas上绘制,实际上它直接操作Surface。但对每个View的变更,它是要通知到ViewRoot,然后ViewRoot获取Canvas。如果绘制完成,surfaceFlinger得到通知,合并Surface成一个Surface到设备屏幕。
名词 UI元数据:(xml上面的信息,父UI元素包含子UI元素)如位置信息,绘制区域
SurfaceFlinger服务:(基本框架的第三层)
Anonymous Shared Memory:匿名共享内存
SharedClient:匿名共享内存块(匿名共享内存的升级版),一个app对应一个
SharedBufferStack:共享内存缓冲堆栈,一个SharedClient里至多有31个
GraphicBuffer:图形缓存区,用于存放UI元数据,(view大小,(绘制)渲染位置等)。
Surface:android 会给予应用程序的activity一个窗口,Android应用的每个窗口对应一个画布(Canvas),即Surface(窗口,绘图表面,有了这个绘图表面才能将UI绘制出来),可以理解为Android应用程序的一个窗口。
SharedBufferStack里的buffer:用于描述UI元数据,UI元数据在GraphicBuffer里存放。


二、
1、android应用程序会调用系统服务SurfaceFlinger为每一个activity分配一个Surface(窗口,绘图表面,有了这个绘图表面才能将窗口的UI渲染出来)。

对于使用Java来开发的Android应用程序来说,它们一般是使用Skia图形库提供的API来绘制UI的。在Skia图库中,所有的UI都是绘制在画布(Canvas)上的,因此,Android应用程序窗口需要将它的图形缓冲区封装在一块画布里面,然后才可以使用Skia库提供的API来绘制UI。
调用SurfaceFlinger服务利用图形缓冲区渲染surface,最后带物理屏幕上去。

过程
1、android应用程序调用SurfaceFlinger为每一个Activity分配一个Surface(绘制表面),有了此绘制表面,才能将许多的UI元素渲染出来。
2、.xml布局文件形成UI元素树。
3、根据.xml布文件和.java的参数配置实现应用侧的测量、布局过程。
4、然后就是SurfaceFlinger服务的过程了。

XML解析过程
1、android应用程序是怎样读取布局文件中的控件及其参数进行绘制的???
[1]Activity填充一个布局文件到自己的窗口上并在绘制表面(Surface)进行绘制。
[2]xml中的控件最终会解析成View或ViewGroup对象。
[3]android 应用程序的表面是由UI元素(View和ViewGroup对象)组成,xml布局文件中定义的每一个UI元素会以属性结构来组织。
[4]然后就是通过递归遍历这些解析好的UI元素进行测量、布局,最后在画布的图形缓存区里进行绘制。

整理


1、Activity通过R文件索引到所需的布局文件,并填充(LayoutInflauter)到自己的窗口。
2、xml中的控件最终会对应成自己View或ViewGroup对象。
3、这些UI元素(即View或ViewGroup对象)通过索引找到自己在xml中的布局参数。
4、然后根据这些布局参数(UI元数据)进行测量和布局操作,然后在画布的图形缓存区内进行绘制操作。
5、然后SurfaceFlinger服务将这些已用的图形缓存区->硬件帧缓冲区进行渲染··最后在物理屏幕上

posted on 2015-12-01 09:12  阿岳  阅读(316)  评论(0编辑  收藏  举报

导航