一、布局加载
inflate->rInflate->createViewFromTag->createView
1.在setContentView方法中,会通过LayoutInflater的inflate方法去加载对应的布局到android.R.id.content中。
2.inflate方法中会调用Resources的getLayout方法去通过IO的方式去加载对应的Xml布局解析到内存中。
内部调用的是 AssetManager的openXmlAssetNative,一个Native方法,通过IO流的方式解析。
方法返回XmlResourceParser,XmlResourceParser继承XmlPullParser, 根据提供的布局资源文件id可读取布局文件中view相关属性。
3.createViewFromTag来创建View的实例,如果创建的是ViewGroup,则会对它的子View遍历重复创建步骤,创建完View对象后,会add到对应的ViewGroup中。
createViewFromTag中会先判断有没有Factory或者Factory2的对象,如果有,则调用Factory的onCreateView方法。这两个类都是接口,其中Factory2是Factory的子接口,都只有唯一的onCreateView方法。
Factory2的onCreateView方法传入了parentView,该方法的作用就是你可以借助它来改造XML中已经存在了的Tag的值。所以Factory2可以达到改造parentView的目的。
如果此时的tag是一个Fragment,则会调用mPrivateFactory的onCreateView方法
最终会调用到AppCompatViewInflater的createView方法。
该方法中,像TextView,ImageView等是通过new AppCompatXXX创建的,这是为了将一些控件变成兼容性控件(例如将 TextView 变成 AppCompatTextView)以便于向下兼容新版本中的效果,在高版本中的一些控件新特性可以在老版本中也能展示。
二、布局绘制
1.绘制
startActivity->ActivityThread.handleLaunchActivity->onCreate ->完成DecorView和Activity的创建->handleResumeActivity->onResume()->DecorView添加到WindowManager->ViewRootImpl.performTraversals()方法,测量(measure),布局(layout),绘制(draw),从DecorView自上而下遍历整个View树。
①在 App 进程中创建PhoneWindow 后会创建ViewRoot。ViewRoot 的创建会创建一个 Surface壳子,请求WMS填充Surface,WMS copyFrom() 一个 NativeSurface。
②响应客户端事件,创建Layer(FrameBuffer)与客户端的Surface建立连接。
③copyFrom()的同时创建匿名共享内存SharedClient(每一个应用和系统服务SurfaceFlinger之间都会创建一个SharedClient)
④当客户端 addView() 或者需要更新 View 时,App 进程的SharedBufferClient 写入数据到共享内存ShareClient中,SurfaceFlinger中的SharedBufferServer接收到通知会将FrameBuffer中的数据传输到屏幕上。
2.刷新
①CPU主要负责Measure、Layout、Record、Execute数据计算工作
绘制的过程 CPU准备数据,通过Driver层把数据交给GPU渲染,Display负责消费显示内容
②GPU负责Rasterization栅格化(将UI元素绘制到屏幕上,即将UI组件拆分到不同的像素上显示)、渲染,渲染好后放到buffer(图像缓冲区域)里存起来.
③Display(屏幕或显示器)会以一定的帧率(16.6ms)刷新,每次刷新,就会从缓存区将图像数据读取显示出来,如果缓存区没有新的数据,就一直用旧的数据,这样屏幕看起来就没有变。
例如:
Ⅰ.文字的显示首先经过CPU换算成纹理,然后再传给GPU进行渲染。
Ⅱ.而图片的显示首先是经过CPU的计算,然后加载到内存当中,最后再传给GPU进行渲染。
双缓存:
屏幕刷新帧率是固定的,每16.6ms从buffer取数据显示完一帧,理想情况是帧率(GPU 在一秒内绘制的帧数,单位 fps)和刷新频率保持一致,即每绘制完成一帧,显示器就显示一帧,但是CPU/GPU写数据是不可控,所以会出现buffer里有些数据还没显示出来就被重写了,导致buffer抓取的帧并不是完整的一帧画面,即出现了画面撕裂。
由于图像绘制和屏幕读取使用的是同个buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。所以引入了双缓存:
让绘制和显示器拥有各自的buffer:GPU 将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Frame Buffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。
什么时候进行两个buffer的交换?
引入VSync(垂直同步),是VerticalSynchronization的简写
如果Back buffer准备完成一帧数据以后就进行交换,此时屏幕还没有完整显示上一帧内容的话,肯定是会出问题。
如果Frame buffer处理完一帧数据以后进行交换,可以。
vsync垂直同步,利用垂直同步脉冲(当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时屏幕没有在刷新,有一段时间空隙,这个时间点就是我们进行缓冲区交换的最佳时间。一旦收到VSync通知(16.6ms触发一次),CPU和GPU 立刻开始计算然后把数据写入Back buffer,可以让CPU/GPU有完整的16.6ms处理数据,减少jank。
三缓冲:
如果界面比较复杂,CPU/GPU的处理时间较长,超过了16.6ms,Back buffer正在被GPU用来处理数据,CPU 则无法准备下一帧的数据计算工作,在jank的阶段空空等待,存在CPU资源浪费。
三缓存就是在双缓冲机制基础上增加了一个Graphic Buffer缓冲区,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个Graphic Buffer所占用的内存。
多增加了一个Buffer给CPU用,让它提前忙起来,这样就能做到三方都有Buffer可用,CPU跟GPU不用争一个Buffer,实现并行处理
三缓冲有效利用了等待vysnc的时间,减少了jank,保证画面的连续性,提高了柔韧性。