前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android之View的诞生之谜

Android之View的诞生之谜

作者头像
陈宇明
发布2020-12-15 12:06:22
3950
发布2020-12-15 12:06:22
举报
文章被收录于专栏:设计模式

作者博客

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的创建流程也略知一二,希望对你有帮助

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

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码个蛋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档