Android之View的诞生之谜

栏目: Android · 发布时间: 6年前

内容简介:Android之View的诞生之谜

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)的源码看一下,注意代码中的注视:

Android之View的诞生之谜

window是什么东东?window是一个抽象类,他只有一个实现类,那就是phoneWindow,phoneWindow是android系统中窗口的顶级类。

我们接着看 getWindow().setContentView(layoutResID);

Android之View的诞生之谜

在渲染我们的布局文件前,先调用了installDecor()来初始化mContentParent,之前也说mContentParent是负责加载我们页面内容的容器,到底是不是呢?我们看下installDecor源码便知道了:

Android之View的诞生之谜

从2处我们看到mContentParent被创建,那么它是如何被创建的呢,他真的是如我们前面所说负责加载内容部分的父容器么?我们来一探究竟,我们看 mContentParent = generateLayout(mDecor)的源码:

Android之View的诞生之谜 Android之View的诞生之谜

小小的发现:从上面的代码我们可以解释很多开发中的技巧,看下面的代码,在加载我们的资源文件前,他就检查了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。如下图:

Android之View的诞生之谜

小结:调用setContentView方法,实例化了DecorView, DecorView有两个子布局,一个是加载顶部状态栏的,一个是加载我们的内容布局的,activity添加的xml就是内容布局的一个字元素

到目前为止,通过setContentView实例化了DecorView并且加载了设置进来的布局文件。然后,并没有发现任何与测量、布局、绘制相关的点,可能你会想,我们不会搞错了吧,其实没有哦,你们想想,setContentView实在,既然还是不可见的,那我为什么要耗费资源去测量呢,你最终能不能露个脸还说不准呢。亏本的买卖咱不干。其实要想知道什么时候开始执行测量等工作,我们可以看下ActivityThread的源码,ActivityThread是android用来管理activity的,这家伙知道的肯定多一些。那么我们就来了解下ActivityThread的执行流程。

首先ActivityThread通过调用handleLaunchActivity启动我们的目标activity

Android之View的诞生之谜

也就是说在performLaunchActivity调用之后,activity的onCreate被调用,我们的资源文件不加载,但是此时还是不可见的,也就还没有进行侧脸之类的事情。

然后我们继续看ActivityThread.handleResumeActivity的源码:

Android之View的诞生之谜

知识补充:

Window是一个抽象的概念,一个Window对应一个View和一个ViewRootImpl;

Window和View是通过ViewRootImpl联系起来的。

ViewRootImpl才是一个View真正实现的动作。

WindowManager中也有一个WindowManagerImpl作为实现的类,负责具体的操作。

跟到这里,我们来总结一下,activity启动过程中,在执行handleResumeActivity时将我们的顶层视图DecorView通过WindowManager挂载到window中。

而WindowManager是个接口类,那么我们看看其实类对象WindowManagerImpl.addView方法

Android之View的诞生之谜

mGlobal其实是WindowManagerGlobal的一个内部实例,接着看WindowManagerGlobal.addView的源码:

Android之View的诞生之谜

我们继续看ViewRootImpl.setView方法的源码

Android之View的诞生之谜

setView完成的工作很多,如声明输入事件的管道,DisplayManager的注册,view的绘画,window的添加等等

作为绘制view的入口,我们来看下requestLayout方法

Android之View的诞生之谜

ViewRootImpl.scheduleTraversals()调用后,系统会发起一个异步消息,然后在异步消息执行过程中调用performTraversals()完成具体的View树遍历;

小子,总算是找到你了,我们来看下胜利的果实吧!

Android之View的诞生之谜

总结

通过上面内容,我们学到了一些小技巧,如移除状态栏的一些步骤,之前我们可能知道,嗯,是的,要在setContentView前调用requestFeature才可以,通过这次分析,我们之前可能是知道要这样子做才行,现在我们知道了为什么要这样子做。是不是写起代码来更踏实了呢?

通过这次分析,我们对于activity的创建流程也略知一二,希望对你有帮助

测量、布局、绘制的工作我们放到下一章节进行学习

如果你看到这里,我要对你说声谢谢,非常感谢你能看完这篇文章

关注微信公众号「码个蛋」,每天更新优质文章

Android之View的诞生之谜


以上所述就是小编给大家介绍的《Android之View的诞生之谜》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML Dog

HTML Dog

Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99

For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具