写在前面
面试系列已经相隔很久没更新了,主要是因为南尘近期搞的「模拟面试」活动花费了太多时间,所以对我的广大读者朋友们深表歉意,不过现在开始依然是一有时间就会更新的。毕竟金三银四,想必想换东家的小伙伴也是比比皆是。
面试场景
什么是 Activity、View、Window?
Activity 是四大组件之一,也是我们的界面载体,可以展示页面;而 View 实际上就是一个一个的视图,这些视图可以搭载在一个 Layout 文件上,通过 Activity 的 setContentView()
方法传递给 Activity;Window 是一个窗体,每个 Activity 对应一个 Window,通常我们在代码中用 getWindow() 来获取它。
你是怎样理解它们三者之间的关系的?
Activity 像一个工匠 ( 控制单元 ),Window 像窗户 ( 承载模型 ),View 像窗花( 显示视图 ) LayoutInflater 像剪刀,Xml 配置像窗花图纸。
比喻挺生动,请问可以通俗一点么?
Activity 下装了一个 Window,Window 下装了 View,呃...
正文
这是我在「模拟面试」活动中一个真实的场景,应试者的答案并不能忽悠到我,因为这个答案网上早就传遍了,但一旦稍微变动一下,应试者的表现就差强人意,很明显,这位小伙伴没对源码进行更加深刻的理解,而只是简单地背下了答案。
我们来直接看看实战中的代码,相信大家都知道 Activity 通过 setContentView()
方法来加载布局,我们来看看 setContentView()
方法到底是怎样做的。
实际上是 getWindow().setContentView()
做的处理,那这个 getWindow()
?
你想的没错,这个 mWindow 实际上就是 PhoneWindow。Window 是一个抽象类,而 PhoneWindow 实际上就是 Window 的实现继承类。我们直接看看 PhoneWindow 的 setContentView()
方法,看看会有什么新发现?
先判断了 mContentParent
是否为空,这个 mContentParent
是什么玩意儿?
这个 mContentParent
是一个 ViewGroup 对象,而从注释中可以明显地看到 Window 中的内容就放置在这里。如果为空,则直接执行 installDecor()
,这里想都不用想都知道是在实例这个 mContentParent
,我们可以直接进入源码来验证我们的猜想。
这里代码挺多,我就不截完了,但逻辑不难,我们先判断 mDecor
是否为 null,如果是,则直接初始化它。然后判断 mContentParent
是否为 null,如果是,则直接通过 mDecor
去初始化 mContentParent
。
这块其实讲到这里大家就差不多了解了,这个问题也就不那么难答。
每个 Activity 包含了一个 Window 对象,这个对象是由 PhoneWindow 做的实现。而 PhoneWindow 将 DecorView 作为了一个应用窗口的根 View,这个 DecorView 又把屏幕划分为了两个区域:一个是 TitleView,一个是 ContentView,而我们平时在 Xml 文件中写的布局正好是展示在 ContentView 中的。
用个图展示一下。