Android WMS及绘制流程

主角:ViewRootImpl、Choreographer、Surfaceflinfer

WMS扮演了什么角色?

作为协调者,协调view布局,绘制;

  1. 在ActivityThread中创建Actiivty后,调用activity.attach()时,创建一个窗体对象PhoneWindow
  2. PhoneWindow创建了一个WMS的代理桥接类WindowManagerImpl对象,作为WMS在app中的代表;
  3. WindowManagerImpl对象中的(mGlobal)WindowManagerGlobal专门和WMS通信,在mGlobal里面获取了到了WMS的Binder:getWindowSession()->WMS::openSession();

setContentView()

  1. 调用PhoneWindow.setContentView(resouseID)
  2. PhoneWindow中:创建mDector:窗体上的整个View:里面有官方的主题布局+用户自己的布局;
  3. PhoneWindow中:创建mContentParent:官方主题布局中提供给用户装载布局的容器:id为content;
  4. 调用mLayoutInflater.inflater(resouseID,mContentParent):
  5. 解析用户的布局xml
  6. 递归调用:解析根布局,通过反射创建根布局;解析子view,通过反射创建view;
  7. 最后PhoneWindow中的mContentParent加载用户的根布局;
  8. 提交view数据

ps:这里递归调用,若嵌套层级太多,会导致栈溢出;因为递归调用不会释放栈;

ViewRootImpl

单例,管理所有View的绘制策略;

注意onCreate.setContentView后view数据已解析并实例化了;

  1. 在状态机为Resume时:
  2. 调用WindowManagerImpl中的mGlobal.addView(view)
  3. addView中创建ViewRootImpl root=new ViewRootImpl():
  4. root.setView(view);
  5. 在setView总调用requestLayout()
  6. requestLayout()请求绘制,编舞者出场

帧速率:

CPU/GPU出图速率;

刷新率:

屏幕刷新速率;

  1. 帧速率>刷新率时,出现丢帧(出图好多张了,但是只显示了开头和结尾两张,中间的丢了)
  2. 帧速率<刷新率,出现卡顿(屏幕刷新好多次了,但是还是显示的第一帧)

Vsync:

垂直同步绘制信号; 因可能硬件帧速率和刷新率不一致,用来同步刷新的问题;

Choreographer编舞者:

负责管理帧率节奏;

  1. 在内部维护了个Haner和Looper,保证绘制发生在UI主线程:Looper.myLooper==mLooper判断是否是主线程,是的话去调同步绘制信号,不是的话发送消息,走主线程去调同步绘制信号
  2. 走native层请求垂直同步信号,实际是找底层驱动要上次绘制的时间
  3. 请求到垂直同步信号后回调onVsync
  4. 走doFrame去逻辑管控, 判断当前时间离上次绘制的时间大于了1帧的时间(16.66毫秒)  就跳帧(卡顿优化有用到),若小于16.66毫秒就再次请求垂直同步信号,防止重叠
  5. 执行callback,让ViewRootImpl去真正绘制,调用ViewRootImpl.performTraversals()

Android WMS及绘制流程_第1张图片

真正的绘制:

ViewRootImpl.performTraversals()

  1. 调用relayoutWindow():
  2. 创建用户java层的surface:只有用户提供的画面数据;
  3. 创建native层的surface:包含用户提供的画面数据(java层的surface)+系统的画面数据(状态栏,电池、wifi等等);
  4. 创建完surface后:依次调用:performMeasure(对应view的onMeasure)、performLayout(onLayout)、performDraw(onDraw);

在performDraw()中:

  1. 将view的数据传至native层的surface
  2. surface中的canvas记录数据
  3. 生成bitmap图像数据(此时数据是在surface中)
  4. 将surface放入队列中;生产者消费者模式;
  5. 通知surfaceflinfer进程去队列中取surface数据
  6. surfaceflinfer拿到不同的surface,进行融合,生成bitmap数据
  7. 将bitmap数据放入framebuffer中,进行展示

Android WMS及绘制流程_第2张图片

简单版总结:

Activity.setContentView(R.layout.resId):

解析xml并实例化;

  1. 调用phoneWindow.setContentView(resId)
  2. 在setContentView中调用installDector():根据不同的主题,找到系统默认的xml,初始化出mDector和mContentParent(反射实例化出对应的ViewGroup)
  3. 初始化完成后,调用mLayoutInflater.inflate(resId,mContentParent):
  4. 解析resId的xml文件,将解析的view反射实例化;递归添加到各节点的viewgroup中;最后将自己定义的xml根布局view添加到mContentParent;

绘制发生时间:

在AMS回调ActivityThread中的handleResumeActivity时,也就是Resume时,而不是onCreate();

  1. 获取PhoneWindow
  2. 获取PhoneWindow中的mDector布局视图view
  3. 将mDector布局视图view传给ViewRootImpl
  4. ViewRootImpl中调用requestLayout()
  5. requestLayout()中依次调用:performMeasure()、performLayout()、performDraw()

Android UI测量、布局、绘制随记_暮冬一十四的博客-CSDN博客

你可能感兴趣的:(Framwork,android)