基于Android6.0的Activity加载View源码分析

作者简介  原创微信公众号郭霖 WeChat ID: guolin_blog

本篇来自程序媛fanfan_story的投稿,透过Android6.0源码,分析了Activity加载View的过程,希望大家喜欢。

fanfan_story的博客地址:

http://blog.csdn.net/zrf1335348191

认识Activity的布局

对于研究布局这种东西,必须要掌握一些视图工具,在这里推荐一个sdk查看视图的工具sdk\tools\hierarchyviewer,随意找一个界面去查看 activity 的 view视图:

在这个 activity 界面中我把导航栏给隐藏了,所以不存在导航栏,根据这张图的话大致可以看到一个 activity 的布局,再结合对 setContentView 的研究,可以总结出 activity 的布局图如下:

从这张 activity 的布局图可以看到:一个 activity 对应一个应用窗口 mWindow,应用窗口 mWindow 包括 activity 的 顶级view是 mDecorView,mDecorView 包括 状态栏statusbar和 导航栏navigationbar 以及要加载 activity 布局的view一一mDecorContentParent,该 view 又包括一个 标题栏titlebar 和 activity的内容布局 contentparent。在 contentParent 中就是该 activity 的 view树。

1. mWindow:Window对象,Window是一个抽象类,是 activity 的顶层外观和行为的代理。会往 windowmanage 中添加该类的一个实例作为 顶层view。window 提供基本的UI代理,比如背景啊,标题区域啊,按键处理啊等等,Window 只有一个实现类 PhoneWindow,所以 mWindow对象 实际是 PhoneWindow对象。当启动一个activity的过程中会初始化一个属于 Phonewindow 的 window对象。Phonewindow对象 的创建在activity 的 attach方法 中。

2. mDecor:DecorView对象,继承自 framelayout,是 window窗口 的 顶级view,包含 window 的装饰。类的定义位于 PhoneWindow.java 中

3. mDecorContentParent:DecorContentParent对象,实现类是 ActionbarOverlayLayout,属于 activity 布局的 最外层view,包括标题栏和activity的内容布局

4. mContentParent:activity 的内容布局,继承自 ViewGroup,用来加载存放 activity 的 view树,如果没有标题栏,那么 mContentparent 的大小会和 mDecorContentParent 相等,以此类推

5. 导航栏:statusbar,对应的 id 为 statusBarBackground,在 PhoneWindow 中会加载,当 window属性 发生改变时会刷新导航栏。但不论是导航栏和状态栏,从这个id也可以看出,PhoneWindow 只是加载他们的 background,即相当于只加载一个view的占位,先告诉应用窗口,系统窗口要求将状态栏和导航栏布局在这里,你不要占用,但此时不会加载导航栏和状态栏的view,只是绘制背景而已。

6. 状态栏:navigationbar,对应的 id 为 navigationBarBackground,在 PhoneWindow 中会加载,当 window属性 发生改变时会刷新状态栏

7. 标题栏:titlebar,对于导航栏,状态栏和标题栏的存在与否,与 window 的属性特征有关,在加载 view 时所以会去判断 window 的属性特征,进而决定是否要加载这三者。

对 activity 的布局大致有个了解之后,就开始去分析 activity 启动后加载view的流程

Activity加载View布局

对于 activity 的布局的加载大致分为两部分,一部分是加载view,另一部分是将view绑定到应用窗口Window。其中这两个步骤中将 view 绑定到 window 是在 启动activity时 完成的操作,是将 mDecor 绑定到 window。然后再往 mDecor 中添加 各种view。对于 activity的启动过程 留待以后进行分析,现在分析加载view一一始于 Activity.Java 的setContentView方法,看一下加载view的流程。

可以看到代码流程很简单,从 Activity.java 的 setContentView方法 进入,到 PhonewWindow.java 的 setContentView方法 进行一系列处理,接下来进入代码进行分析

Activity.java 的 setContentView 方法

代码路径\Android\frameworks\base\core\java\android\app

源码中对该方法的解释是,从一个 layout 文件中取出 view 设置成 activity 的 content,该资源文件会被填充,并遍历文件中的 所有view 添加到 activity。意思就是填充一个资源文件,加载view。做了两件事儿:

一是 getWindow 获取到 Window对象,然后去调用 Window 的 setContentView方法。

二是 initWindowDecorActionbar(),创建 actionbar对象,填充 mDecor 下的 actionbarView,并把 view 加载上去(博主猜测是在 Window 的 setContentView方法 中只是填充一个 actionbar 的占位,然后 initWindowDecorActionbar() 完成 view 的加载)

重点研究第一步:getWindow().setContentView方法。

首先一个问题,为什么我要说 getWindow.setContentView 调用的是 PhoneWindow 中的setContentView方法?

解疑:查看getWindow方法:

publicWindowgetWindow() {

returnmWindow;}

返回的是 activity 的 mWindow对象,对于 mWindow对象 的创建也是在 Activity.java 中的 attach方法 中:

同时,进入到 Window.java 中也可以看到这一点:

源码中对于 Window类 的说明是:

Window 是一个抽象类,是最顶层的窗口的外观和行为的代理,window 的实例应该被作为最顶层的UI添加到 WindowManage 中。Window 提供了基本的ui,比如背景,标题区域,默认的按键处理过程等等。Window 只有一个唯一的实现类 PhoneWindow,当需要 Window对象 时需要去初始化 PhoneWindow。

至此,对于 Activity 中的 mWindow对象 大致有了一个清晰的认识了:他是个 PhoneWindow对象,Window.java 中方法的实现在 PhoneWindow.java 中

PhoneWindow.java中的setContentView方法

代码路径\android\frameworks\base\core\java\com\android\internal\policy

先来总结一下代码的流:

在新启动一个 activity 时 mContentParent 还未绑定id,此时 mContentParent 为null。从代码流程图中可以看出 setContentView 做了三件事:

installDecor 实例化 DecorView对象 和 mContentParent对象

填充 layout 文件

通知 activity 布局已经改变

为什么说是通知 activity 布局已经改变呢?这是因为在 Activity.java 的 attach方法 中 mWindow对象 设置了 callback 为this,所以在 getCallback 时获取到的 cb 为当前与该 window 对应的 activity。

PhoneWindow.java中的installDecor方法分析

实例化 DecorView对象 和 mContentParent对象

在创建一个 activity 时 mDecor 和 mContentParent 均为null

借助 generateDecor 方法实例化 mDecor,即获取到 activity 的 最顶级的view

借助 generateLayout 方法实例化 mContentParent对象,并且根据 window 的不同 Feature 来选择对应的布局文件(总之,generatelayout 其实就是根据当前的 window 的特征属性 feature 来加载内容布局,并获取到当前布局的 最外层view。也就是说

generatelayout 本质就是根据 activity 的 theme主题 来找到对应的xml布局并且获取到id为 content 的 ViewGroup赋给 mContentParent

获取到 mDecorParent对象,并且根据 getLocalFeature 获取到的 Feature 来设置(这也就说明了在自定义Activity时为什么要将 getWindow.requestFeature方法 写在 setContentView方法 之前)

对 title 进行隐藏或者是设置内容的操作

如果需要切入切出动画,那么就获取到各种动画资源

接下来对 installDecor 中某些代码做一些分析:

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

用于对焦点的传递设置:只有当 子view 不想获取焦点时 mDecor 才会去获取焦点

mDecor.postOnAnimation(mInvalidatePanelMenuRunnable)

去开启初始化menu菜单的线程

在这里说明一句,为什么 requestFeature 要写在 setContentView 前面,这是因为在调用 setContentView 时会获取到 window 的各种 feature 进行一些判断设置。

PhoneWindow.java中的generateLayout方法研究

第一步:首先是获取到 window 的布局style

TypedArraya=getWindowStyle();

第二步:获取到各种属性并进行 requestFeature 的设置

第三步:通过获取到的 window 的布局去获取 window 的各种属性,并根据 window 的各种属性去选择不同的 layout 的文件,比如标题栏是否隐藏,window 是悬浮窗还是全屏等等问题。当然因为在3.0和4.0以及5.0对于menukey的支持不同,所以会有一个与版本相关的一个判断。至于这个版本之间有什么不同可以参考总结说明中列出来的文件。

其实 generatelayout 就做了一件事,那就是根据 window 的各种属性去获取不同的xml文件。

总结

setContentView 执行流程中主要涉及到3个类 PhoneWindow.java,Activity.java 和 Window.java

Window 和 windowmanager 中的 各种feature 和 flag的style 对应的各种含义以及动画 style在\android\android\frameworks\base\core\res\res\values\attrs.xml 文件中有注释说明

在 menu键 的设置中涉及到了版本问题,包括 3.0,4.0 和 5.0 分别有对应的不同处理,参考 \android\android\frameworks\base\core\java\android\os\Build.java 可以看到注释有说明各版本有什么不同

至于为什么说 mDecor 是 最外层view,是因为在 generateLayout 方法中 mDecor 将填充该xml文件的 view一一mContentRoot 添加了进来。

Activity在启动加载布局的操作

创建 DecorView 的布局:setContentView 的流程基本是用来创建 DecorView 的布局

将布局添加到 window 窗口:在 Activity 的启动过程中,会将应用窗口添加到 WindowManager 中进行统一管理,以及绑定 DecorView

对于状态栏和导航栏,是在每次 window 属性发生变化时会去更新,但是只是设置了一个背景色,只是占位用,没有加载这些view


文章原创作者GuoLin 书籍推荐

郭林大神原创android 书籍:《第一行代码 android》

淘宝链接:

https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容