likes
comments
collection
share

【面试官爸爸】来给我讲讲View绘制?

作者站长头像
站长
· 阅读数 51

前言

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

“来面试的?”

“对对对” 我赶紧答应

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

【面试官爸爸】来给我讲讲View绘制?

起一个好头

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

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

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

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

什么是 ViewRootImpl

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

什么是 ViewRootImpl 呢?

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

【面试官爸爸】来给我讲讲View绘制?

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

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

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

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

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

【面试官爸爸】来给我讲讲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 结束后

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

【面试官爸爸】来给我讲讲View绘制?

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

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

ViewRootImpl 是如何绘制 View 的

我们再来看一下 setView 方法

【面试官爸爸】来给我讲讲View绘制?

简单来说 setView 做了三件事

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

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

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

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

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

【面试官爸爸】来给我讲讲View绘制?

考考你对知识的运用

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

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

【面试官爸爸】来给我讲讲View绘制?

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

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

MeasureSpec 的理解

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

这个问题看似很简单死板,其实是想考察对 View 测量的理解。

View 的大小不仅仅取决于自身的宽高,还取决于父 View 的大小和测量模式。一个 200200 的父 View 是不可能容纳一个 300300 的子 View 的,父 View 的 wrap_content 和 match_content 也会影响子 View 的大小。

所以 View 的 measure 函数其实应该有 4 个参数:父 View 的宽父 View 的高宽的测量模式高的测量模式

Android 这里用了一个巧妙的设计,用一个 Int 值来表示宽/高的测量模式和大小。一个 int 有 32 位,前 2 位表示测量 MODE,后 30 位表示 SIZE。

为什么要用 2 位表示 MODE 呢?因为 MODE 只有 3 种呀,UNSPECIFIED,EXACTLY,AT_MOST,小傻瓜。

【面试官爸爸】来给我讲讲View绘制?

“不错啊小伙子,那我自定义一个 View 的时候,如果不对 MeasureSpec 做处理。使用这个 View 时宽高传入 wrap_content,结果会怎么样?”

这个考察的就是 View 绘制的实际运用了。当我们自定义一个 View 时,如果继承的是 View,measure 方法走的就是 View 默认的逻辑

【面试官爸爸】来给我讲讲View绘制?

所以当我们自定义 View 时,如果没有对 MODE 做处理,设置 wrap_content 和 match_content 结果其实是一样的,View 的宽高都是取父 View 的宽高。

再来点细节

“呦呵,那你说说 invaliate 和 requestlayout 方法的区别”

前面我们说到,ViewRootImpl 作为顶级 View 负责 View 的绘制。所以简单来说,requestlayout 和 invaliate 最终都会向上回溯调用到 ViewRootImpl 的 postTranversals 方法来绘制 View。

不同的是 requestlayout 会绘制 View 的 measure,layout 和 draw 过程。invaliate 因为只添加了绘制 draw 的标志位,只会绘制 draw 过程。

这也能考算法

“可以可以,看来 View 绘制这块你理解的不错嘛。来考你个小算法,实现一下 findViewbyid 的过程”

一般对开发而言,算法的考察都不会太深,主要是常见算法的简单使用。目的是对业务中遇到的一些问题有更好的解决思路。像这个问题其实是想考察一下递归算法的简单使用。

【面试官爸爸】来给我讲讲View绘制?

“小伙子准备的不错嘛,好了,View 绘制这块我没有什么问题了,我们来聊聊 View 事件处理吧....”

View 绘制相关的问题到这里就结束啦。如果大家觉得还不错的话,欢迎各位点赞,收藏,关注三连~

后续我还会继续更新【面试官爸爸】这个系列,包括事件处理HandlerActivity 启动流程编译打包优化Context 等面试最常问的问题。如果不想错过,欢迎点赞,收藏,关注我!

也可以关注我的公众号 @方木Rudy 里面不仅有技术,还有故事和感悟。你的支持,是我不断创作的动力!

哦对了,是不是看完一遍觉得不够爽?杂七杂八说一大堆复习的时候一点也不轻松! 嘿嘿,我把上面提到的所有问题整理成了思维导图,方便各位观众老爷复习 ~

【面试官爸爸】来给我讲讲View绘制?

我是方木

一个在互联网世界挣扎向上的打工人

努力生活,努力向前

欢迎来公众号找我玩~ @方木Rudy

转载自:https://juejin.cn/post/6979395482946633758
评论
请登录