内容简介:Android之View的诞生之谜
作者博客
http://www.cherylgood.cn
前言
hello,大家好,平时大家都说自定义view,这次给大家带来有关view的相关知识,希望你喜欢!
作为一名正在岗位上的Android开发者,工作中常常需要我们使用自定义View去实现一些天马行空的效果,而作为一名正在寻找工作的Android开发者而言,面试过程中自定义View的相关知识点也是热门的面试题目之一哦,好东西我们怎么能错过呢;
作为Android开发者,我们应该不断的丰富自身的知识体系结构,加强Android开发内功的修炼(个人看法:学习Android内部底层一些的知识,可视为内功。而对于api的灵活使用,可视为招式)。
本次我们将来探索自定义View的内功心法之自定义View的死亡三部曲:测量、布局、绘制。
在了解死亡三部曲之前,我们先从上层的视角看下死亡三部曲的执行流程。
Activity的布局文件是如何被加载的?
我们的activity中的视图是什么时候被加载的呢?setContentView(R.layout.main);这个方法你肯定会很眼熟:其实我们的activity就是通过这个方法加载我们的布局文件进行视图的渲染。那么我们就从他入手吧。
我们进入setContentView(R.layout.main)的源码看一下,注意代码中的注视:
window是什么东东?window是一个抽象类,他只有一个实现类,那就是phoneWindow,phoneWindow是android系统中窗口的顶级类。
我们接着看 getWindow().setContentView(layoutResID);
在渲染我们的布局文件前,先调用了installDecor()来初始化mContentParent,之前也说mContentParent是负责加载我们页面内容的容器,到底是不是呢?我们看下installDecor源码便知道了:
从2处我们看到mContentParent被创建,那么它是如何被创建的呢,他真的是如我们前面所说负责加载内容部分的父容器么?我们来一探究竟,我们看 mContentParent = generateLayout(mDecor)的源码:
小小的发现:从上面的代码我们可以解释很多开发中的技巧,看下面的代码,在加载我们的资源文件前,他就检查了FEATURE_ACTION_BAR和FEATURE_NO_TITLE属性,所以我们想让activity全屏或者没有actionBar的话,必须在setContentView调用之前设置。
接下来我们回到前面
setContentViewgetWindow().setContentView(layoutResID);方法,继续看mLayoutInflater.inflate(layoutResID, mContentParent); 这个方法 mContenParent我们已经知道是什么了,然后通过mLayoutInflater.inflate,我们的布局就被渲染出来了。
DecorView补充: DecorView是整个ViewTree的最顶层View,我们之前分析过她是是个FrameLayout布局,代表了整个应用的界面。在该布局下面,有标题view和内容view这两个子元素,而内容view则是上面提到的mContentParent。如下图:
小结:调用setContentView方法,实例化了DecorView, DecorView有两个子布局,一个是加载顶部状态栏的,一个是加载我们的内容布局的,activity添加的xml就是内容布局的一个字元素
到目前为止,通过setContentView实例化了DecorView并且加载了设置进来的布局文件。然后,并没有发现任何与测量、布局、绘制相关的点,可能你会想,我们不会搞错了吧,其实没有哦,你们想想,setContentView实在,既然还是不可见的,那我为什么要耗费资源去测量呢,你最终能不能露个脸还说不准呢。亏本的买卖咱不干。其实要想知道什么时候开始执行测量等工作,我们可以看下ActivityThread的源码,ActivityThread是android用来管理activity的,这家伙知道的肯定多一些。那么我们就来了解下ActivityThread的执行流程。
首先ActivityThread通过调用handleLaunchActivity启动我们的目标activity
也就是说在performLaunchActivity调用之后,activity的onCreate被调用,我们的资源文件不加载,但是此时还是不可见的,也就还没有进行侧脸之类的事情。
然后我们继续看ActivityThread.handleResumeActivity的源码:
知识补充:
Window是一个抽象的概念,一个Window对应一个View和一个ViewRootImpl;
Window和View是通过ViewRootImpl联系起来的。
ViewRootImpl才是一个View真正实现的动作。
WindowManager中也有一个WindowManagerImpl作为实现的类,负责具体的操作。
跟到这里,我们来总结一下,activity启动过程中,在执行handleResumeActivity时将我们的顶层视图DecorView通过WindowManager挂载到window中。
而WindowManager是个接口类,那么我们看看其实类对象WindowManagerImpl.addView方法
mGlobal其实是WindowManagerGlobal的一个内部实例,接着看WindowManagerGlobal.addView的源码:
我们继续看ViewRootImpl.setView方法的源码
setView完成的工作很多,如声明输入事件的管道,DisplayManager的注册,view的绘画,window的添加等等
作为绘制view的入口,我们来看下requestLayout方法
ViewRootImpl.scheduleTraversals()调用后,系统会发起一个异步消息,然后在异步消息执行过程中调用performTraversals()完成具体的View树遍历;
小子,总算是找到你了,我们来看下胜利的果实吧!
总结
通过上面内容,我们学到了一些小技巧,如移除状态栏的一些步骤,之前我们可能知道,嗯,是的,要在setContentView前调用requestFeature才可以,通过这次分析,我们之前可能是知道要这样子做才行,现在我们知道了为什么要这样子做。是不是写起代码来更踏实了呢?
通过这次分析,我们对于activity的创建流程也略知一二,希望对你有帮助
测量、布局、绘制的工作我们放到下一章节进行学习
如果你看到这里,我要对你说声谢谢,非常感谢你能看完这篇文章
关注微信公众号「码个蛋」,每天更新优质文章
以上所述就是小编给大家介绍的《Android之View的诞生之谜》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。