写点什么

Android 面试官:“来给我讲讲 View 绘制?

用户头像
Android架构
关注
发布于: 1 小时前

前言




迎面走来的一位中年男子,他一手拿着保温杯,一手抱着笔记本电脑,顶着惺忪的睡眼,不紧不慢地走着,不多的几根头发在他头顶自由飞翔。过了一会,他面对着我坐下,放下电脑和保温杯,边揉眉头边对我说


“来面试的?”


“对对对” 我赶紧答应


“行吧,那你讲讲 View 的绘制流程吧”



起一个好头




View 的绘制流程应该是每个初高级 Android 攻城狮必知必会的东西,也是面试必考的内容,每个人都有不同的回答方式。


简单点譬如 measure,layout,draw 分别对应测量,布局,绘制三个过程,高明一点的会引申出 Handler,同步屏障,View 的事件传递,甚至 activity 的启动过程。掌握哪些东西,如何回答,能够给面试官一种清晰,了然于胸的感觉,同时又不会被追问三连一问三不知。各位老爷听我慢慢道来。


“噢噢,View 的绘制啊。这个可以分为顶级 View 的绘制,Viewgroup 的绘制和 View 的绘制三个方面。顶级 View 就是 ViewrootImpl”


将回答的内容分类是体现自己思考能力和知识结构的重要表现。


什么是 ViewRootImpl




相比 Viewgroup 和 View,ViewRootImpl 可能更为陌生,实际开发中我们基本用不到它。那么


什么是 ViewRootImpl 呢?


从结构上来看,ViewRootImpl 和 ViewGroup 其实是一种东西



它们都继承了 ViewParent。ViewParent 是一个接口,定义了一些父 View 的基本行为,比如 requestlayout,getparent 等。不同的是,ViewRootImpl 并不会像 ViewGroup 一样被真正绘制在屏幕上。在 activity 中,它是专门用来绘制 DecorView 的,核心方法是 setView


回答的好好的偏要问我其他问题




提到 DecorView,就不得不说一下 window 了。面试中常常我们提到一个点,或者一个词,面试官会马上引申出这个知识点相关的问题。如果我们只是死记硬背,自顾自背一堆绘制相关的东西而回答不上来,会大大减分。所以储备与必问内容相关的东西对面试和自己的知识体系很有帮助。不少老爷被面试的时候都会被问到一个问题


“activity,window,View 三者之间的关系是什么?”


我们可以通过一张图来说明。



如图所示,window 是 activity 里的一个实例变量,本质是一个接口,唯一的实现类是 PhoneWindow。


activity 的 setContentView 方法实际上是就是交给 phonewindow 去做的。window 和 View 的关系可以类比为显示器显示的内容


每个 activity 都有一个“显示器” window,“显示的内容”就是 DecorView。这个“显示器”定义了一些方法来决定如何显示内容。比如 setTitleColor setTitle 是设置导航栏的颜色和 title , setAllowReturnTransitionOverlap 设置进/出场动画等等。


所以 window 是 activity 的一个成员变量,window 和 View 是“显示器”和“显示内容”的关系。


这就是他们的关系


View 是怎么绘制的




“呦呵,不错嘛,这个比喻不错,看来平时还挺爱思考的。行,你继续说说 View 是怎么绘制的”


在整个 activity 的生命周期中,setContentView 是在 onCreate 中调用的,它实现了对资源文件的解析,完成了 xml 文件到 View 的转化。那么 View 真正开始绘制是在哪个生命周期呢?


答案是 onResume 结束后


他们的关系在源码中一目了然。



从源码中可以看到,onResume 之后,ActivityThread 通过调用 activity 中 windowmanager 的 addView 方法,将 decorView 传入到 ViewRootImpl 的 setView 方法中,通过 setView 来完成 View 的绘制。


问题又来了,setView 到底有什么魔法,为什么他就能完成 View 的绘制工作呢?


ViewRootImpl 是如何绘制 View 的




我们再来看一下 setView 方法



简单来说 setView 做了三件事


① 检查绘制的线程是不是创建 View 的线程。这里可以引申出一个问题,View 的绘制必须在主线程吗?


② 通过内存屏障保证绘制 View 的任务是最优先的


③ 调用 performTraversals 完成 measure,layout,draw 的绘制


看到这里,ViewRootImpl 的绘制基本就完成了。其实这也是面试官希望听到的内容。考察的是面试者对 View 绘制体系的理解。


后续 ViewGroup 和 View 的绘制其实是 performTraversals 对整个 ViewTree 的绘制。他们的关系可以用下面这张图表示



考考你对知识的运用




“不错不错,看来你对 Viewrooti


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


mpl 的绘制过程掌握的不错嘛,你刚才提到 View 的绘制是在 onResume 之后才开始的,那为什么我在 onCreate 中调用 View.post 方法可以得到 View 的宽高呢”


这个问题乍看挺唬人的。其实看一眼源码大概就明白了



View.post 会判断当前 View 是否已经被添加到 window 上。如果添加了则立即执行 runnable,如果没有被添加则先放到一个队列中存储起来,等添加到 window 上时再执行。


而 View 被测量完成后才会 attachToWindow。所以当 post 的 runnable 执行时,View 已经绘制完成了。


MeasureSpec 的理解




“可以可以。看来这个小细节你注意到了。再问你个简单的问题,你刚才说到 measure 方法吧,那你说说什么是 MeasureSpec?为什么测量宽高要用它作为参数呢?”

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android面试官:“来给我讲讲View绘制?