Android之View的诞生之谜

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

内容简介: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的诞生之谜》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

程序员健康指南

程序员健康指南

Joe Kutner / 陈少芸 / 人民邮电出版社 / 2014-9-20 / 31.60元

本书是为程序员量身制作的健康指南,针对头痛、眼部疲劳、背部疼痛和手腕疼痛等常见的问题,简要介绍了其成因、测试方法,并列出了每天的行动计划,从运动、饮食等方面给出详细指导,帮助程序员在不改变工作方式的情况下轻松拥有健康。 本书适合程序员、长期伏案工作的其他人群以及所有关心健康的人士阅读。一起来看看 《程序员健康指南》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具