总架构
CPU:负责计算数据,把计算好的数据交给GPU。计算数据指的是View树的绘制过程,也就是Activity对应视图树从根布局DecorView开始遍历View,分别执行测量、布局、绘制三个操作过程
GPU:对图形数据进行渲染,渲染后放到buffer里存起来
display(可称为屏幕或者显示器):负责把buffer里的数据呈现到屏幕上
简单来说就是CPU/GPU准备好数据,存入buffer,Display每隔一段时间去buffer里面取数据,然后显示出来。Display每次读取的频率是固定的,比如16ms一次,但是CPU/GPU写数据是完全无规律的
我们常说的16.6ms刷新一次屏幕其实就是底层以固定的频率将buffer中的屏幕数据显示出来
Activity启动,生命周期方法顺序执行,屏幕渲染流程也开始
- ActivityThread/handleLaunchActivity/performLaunchActivity/创建activity/调用attach()
Activity.attach/new PhoneWindow/mWindow.setWindowManager/拿到WindowManagerImpl实例,持有phoneWindow的引用/
2件事情:new PhoneWindow实例;和windowManagerService跨进程通讯拿到windowManager实例
-
onCreate()/onStart()
setContentView
3件事情:new DecorView;mContentParent=R.id.content; mLayoutInflater.inflate(layoutResID, mContentParent); -
handleResumeActivity/onResume()
3件事情:
在 ActivityThread 中有 handleResumeActivity() 方法
activity.mDecor = decor
onresume–setVisible_makeVisible wm.addView(mDecor)—/WindowManagerImpl.addView/WindowManagerGlobal.addView
root = new ViewRootImpl,root.setView—requestlayout
Android 界面都是activity组件来加载,在activity生命周期方法执行的顺序中,我们实现了view的渲染过程。
每打开一个activity,会new phoneWindow,new DecorView,new ViewRootImpl
- Activity.onCreate/setContentView/getWindow=phoneWindow/setContentView/new DecorView/FrameLayout—mContentParent=generateLayout(mDecor)/mContentParent.addView/ViewGroup.addView/requestLayout,invalidate()//当mParent=null,不会去执行view绘制//mParent.invalidateChild()
(/ViewRootImpl.invalidateChild/ invalidateChildInParent/checkThread//ViewRootImpl.performTrvaersals)
DecorView 什么时候被添加到 PhoneWindow 上。在 ActivityThread 中有 handleResumeActivity() 方法
activity.mDecor = decor
- handleResumeActivity/Activity.onResume/把DecorView添加到windowManager,wm.addView(Decor)/WindowManagerImpl.addView/WindowManagerGlobal.addView/初始化
ViewRootImpl,root/ViewRootImpl.setView(view/DecorView),ViewRootImpl持有DecorView的引用/requestLayout(),进行view的绘制流程/view.assignParent(this),将当前ViewRootImpl对象赋值给了DecorView/View.assignParent/给mParent赋值
- WindowManagerImpl.addView方法/WindowManagerGlobal.addView//参数检查adjustLayoutParams—LayoutParams//初始化ViewRootImpl,把ViewRootImpl赋值给了DecorView.mParent//ViewRootImpl.setView//addToDisplay/WMS的addWindow/分配surface/SurfaceFlinger/把这些Surface混合并绘制到屏幕上
requestLayout和invalidate区别
requestLayout方法会导致View的onMeasure、onLayout、onDraw方法被调用;invalidate方法则只会导致View的onDraw方法被调用
view绘制
CPU
GPU
display
垂直同步信号
ViewRootImpl//view树的顶层
AttachInfo 创建,这个类很重要,之前说的 软解时 Canvas 的保存和复用,还有 View.post() 方法执行等等
TraversalRunnable/doTraversal()/performTraversals()
Add view/requestLayout()
windowManager/WindowManagerGlobal/add、update、remove
Window
View
ViewRootImpl 被 WindowManagerGlobal 创建,
ViewRootImpl 和 Window 的对应关系是多对一,一个 Window 可以有多个 ViewRootImpl
// 调用 windowManager.addView()
wm.addView(decor, l);
root.setView(view, wparams, panelParentView),然后在该方法内部调用requestLayout执行view的三大流程。随后会通过Binder对象WindowSession将Window的添加请求发送给WindowManagerService
https://blog.csdn.net/jiang19921002/article/details/78977560
每一个activity第一次绘制
view有变化刷新
SurfaceFlingger
每一个window都对应一个画/Surface,SurfaceFlingger把各个Surface显示到同一个屏幕上
Android手机屏幕上显示的内容就是由一个个Window组合而成的。顶部的状态栏是一个window,底部的导航栏也是一个window,中间区域也是一个window,toast和dialog也都对应一个自己的window,都由WMS管理。
SurfaceView
首先列举最常见的和View的区别
- View的绘图效率低,主要用于动画变化较少的程序,必须在主线程更新
- SurfaceView绘图效率高,用于界面更新频繁的程序,一般在子线程更新
- SurfaceView拥有独立的Surface(绘图表面),即它不与其宿主窗口共享同一个Surface
- SurfaceView使用双缓冲机制,播放视频时画面更流畅
- 每个窗口在SurfaceFlinger服务中都对应有一个Layer,用它来描述它的绘制表面。对于那些具有SurfaceView的窗口来说,每一个SurfaceView在SurfaceFlinger服务中还对应于一个独立的Layer或者LayerBuffer,用来单独描述它的绘图表面,以区别于它的宿主窗口的绘图表面。所以SurfaceView的UI就可以在一个独立的线程中进行绘制,可以不占用主线程资源,它产生原因也是为了应对耗时的操作,例如Camera X。
SurfaceView与View的区别,使用场景
View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,比如频繁刷新
View在主线程中对画面进行刷新,SurfaceView通常会通过一个子线程来进行页面的刷新
View在绘图时没有使用双缓冲机制,SurfaceView在底层就已经实现了双缓冲机制
RemoteView在哪些功能中使用
远程访问和控制PC机或者服务器的远程控制软件
题目
- View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view?
从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。
- view的测量宽高和实际宽高有区别吗?
多次测量情况下,不一定相等的
实际宽高是在layout流程里确定的
- view的measureSpec 由谁决定?顶级view呢?
由view自己的layoutParams和父容器一起决定的measureSpec
- 为什么在activity的生命周期里无法获得测量宽高?有什么方法可以解决这个问题吗?
因为measure的过程和activity的生命周期 没有任何关系。你无法确定在哪个生命周期执行完毕以后 view的measure过程一定走完
//重写activity的这个方法
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = tv.getMeasuredWidth();
int height = tv.getMeasuredHeight();
Log.v("burning", "width==" + width);
Log.v("burning", "height==" + height);
}
}
- draw方法 大概有几个步骤?
一共是4个步骤, 绘制背景---------绘制自己--------绘制chrildren----绘制装饰
- View的绘制过程
一个View要显示在界面上,需要经历一个View树的遍历过程,这个过程又可以分为三个过程,也就是自定义View中的三要素:大小,位置,画什么,即onMesure(),onLayout(),onDraw()。
1.onMesure()确定一个View的大小;
2.onLayout()确定View在父节点上的位置;
3.onDraw()绘制View 的内容;
- 如何自定义ViewGroup
1.指定的LayoutParams
2.onMeasure中计算所有childView的宽和高,然后根据childView的宽和高,计算自己的宽和高。(当然,如果不是wrap_content,直接使用父ViewGroup传入的计算值即可)
3.onLayout中对所有的childView进行布局。
- View中onTouch,onTouchEvent,onClick的执行顺序
dispatchTouchEvent—->onTouch—->onTouchEvent—–>onClick。在所有ACTION_UP事件之后才触发onClick点击事件,Onclick 事件是在Up 事件中触发的
-
Onclick 事件的触发条件
setOnClickListener
View 没有重写 OnTouchEvent ( 默认情况下 所有触摸事件返回都是clickable,也就是如果View 是可点击的,那么它会消耗一切事件)
手指没有移动出View的范围。
有抬起动作 -
为什么手指移出 View 的范围,不会触发OnClick?
onTouchEvent ACTION_MOVE动作处理,当pointInView(x, y, mTouchSlop)为false 的时候 ,也就是手指移出View范围,setPressed(false),也就是设置取消了Pressed状态
简述Android的View绘制流程,Android的wrap_content是如何计算的?
https://www.cnblogs.com/duanweishi/p/4301742.html
WindowManager.addView(),View.getParent()是谁?
View 绘制原理会问 requestLayout() 和 invalidate() 什么区别?什么情况下 requestLayout() 会执行 onDraw() 方法?
invalidate、requestlayout是否会调用ondraw?
https://blog.csdn.net/lhl5281/article/details/80136240
#@ 一 是什么,怎么用,为什么
一个UI组件渲染/刷新的流程,细节
学习参考博客
https://www.jianshu.com/p/610cfc29774e//分析ViewRootImpl.setView
http://liuwangshu.cn/tags/WindowManager//刘望舒
https://juejin.im/post/5abd94536fb9a028b92d3c80
https://juejin.im/post/5d260b1c6fb9a07ef4442fb9
https://www.jianshu.com/p/c5d200dde486
https://www.jianshu.com/p/1b12940c55bd
https://juejin.im/entry/59209adc570c350069a54f01
https://juejin.im/entry/56f7eb386be3ff005cfcaaed//Android View 绘制 13 问 13 答
https://blog.csdn.net/Rain_9155/article/details/88829992
Activity界面显示全解析
https://www.jianshu.com/p/65295b2cb047
LayoutInflater#inflate 源码解析
https://www.jianshu.com/p/49fca4c06eff