Android进阶 - 视图层级实时分析

android_7.1.png

摘要

在App运行过程中,我们的视图层级可能会由于用户的操作一直在发生改变,甚至可能会有一些出乎预料的变化,本文将会介绍如何进行Android视图实时分析,分析View的视图层级及属性变化。

引题

注:
1.笔者分析代码使用的API版本为API 25 (Android 7.1)
2.笔者使用的模拟器为Android 7.1

首先,笔者先来一个简单的Demo实例。我们使用Android Studio新建一个Empty Android工程,跑一下程序,界面如下图所示:

activity.png

接下来,我们要对视图层级进行分析,但分析之前先给各位介绍两个视图分析工具。

1.Android SDKtools包下的hierarchyviewer,最终展现的视图效果如下:

hierarchyviewer.png

2.Android Studio也有自带的视图分析工具 Layout Inspector(布局检查器),打开方式如下图所示:

layout_inspector.png

可以看到Layout Inspector最右侧的属性栏可以查看每一个View的所附带的属性及属性值

注:笔者推荐Android Studio开发者可以使用Layout Inspector。

正文

一.视图层级分析

从根视图开始分析视图层级,如下图所示:

decorview.png
  • 我们可以看到视图的根布局是DecorView,宽度和高度为模拟器屏幕宽高
  • DecorView中包含3个子View:LinearLayout、View、View

DecorView的第一个子View(LinearLayout), 如下图所示:

linearlayout.png
  • LinearLayout的高度与屏幕高度相比少了96像素,从layout_bottomMargin属性可以知道这96像素用来预留底部边界了。

DecorView的第二个子View(View),如下图所示:

navigationbar.png
  • View的ID值表明了这个视图的作用:底部导航栏背景
  • 这个View的高度是96像素(属性列表间距较大,截图没有截到)

DecorView的第三个子View(View),如下图所示:

statusbar.png
  • View的ID值表明了这个视图的作用:状态栏背景
  • 这个View的高度是48像素(属性列表间距较大,截图没有截到)

插入一点剧情:
有朋友可能会问,是不是只要知道这个ID值(statusBarBackground),我们就可以拿到这个状态栏背景View,之后想怎么操作这个View都可以?

答案:可以。但这里有一些注意点:

  • 只有在API 21(Android 5.0)以上才能获取到该"状态栏View",如下图所示:


    get_statusbar.png
  • 在onCreate方法里直接获取该"状态栏View"值为null,如下图所示:


    get_statusbar_fail.png
  • 当视图已经显示出来时,可以拿到这个"状态栏View",如下图所示:


    get_statusbar_success.png
  • 简单说明一下在onCreate方法里直接获取"状态栏View"值为null的原因:
    findViewById(int id) 这个方法最终会走的DecorView(ViewGroup)的findViewTraversal(int id)方法进行View遍历,根据id值查找子View。我们Debug走到这个方法时发现DecorView里只有一个LinearLayout,另外两个View还没有加载进来,如下图所示:
    statusbar_reason.png

    结论:当我们在OnCreate方法里执行完setContentView(int id)方法后,"状态栏View"和"底部导航栏View"还没有添加进DecorView,此时生成的DecorView并不是最终显示的DecorView。

至此,DecorView的最外层View全部分析完毕。


接下来,分析DecorView的第一个子View(LinearLayout),如下图所示:

linearlayout_detail.png
  • LinearLayout包含两个子View:ViewStub和FrameLayout
  • ViewStub显示的文字颜色为灰色,说明该View没有在当前视图上显示出来。

注:ViewStub继承自View,是一种视图容器,一般用于对布局资源的加载流程进行优化。

ViewStub的属性信息,如下图所示:

viewstub.png
  • ViewStub的getVisibility属性值为 GONE (ViewStub处于隐藏状态)

FrameLayout的属性信息,如下图所示:

framelayout.png
  • FrameLayout的高度值为1136px,相比于父布局LinearLayout又少了48px
  • 从mTop属性可以知道,FrameLayout在布局时顶点坐标高度从48px开始,空出了状态栏的高度

接下来,继续分析FrameLayout的子View,如下图所示:

actionbaroverlaylayout.png
  • FrameLayout只有一个子View:ActionBarOverlayLayout
  • ActionBarOverlayLayout的宽度和高度与FrameLayout保持一致。
  • ActionBarOverlayLayout有两个子View:ContentFrameLayout和ActionBarContainer

ContentFrameLayout的视图属性,如下图所示:

content_framelayout.png
  • ContentFrameLayout的高度相比于父布局减少了112px
  • 从layout_topMargin属性可以看出,这112px用于预留顶部边界,空出了标题栏的高度
content_framelayout2.png
  • ContentFrameLayout的mID属性值为content(android.R.id.content)
  • ContentFrameLayout里的子View就是我们activity_main.xml中的视图了。

注:这里有个很有趣的地方,我们activity_main.xml文件里用的是TextView,但是最后却被转成了AppCompatTextView。限于篇幅,笔者重起了一篇文章Android进阶 - 源码中的视图转换,有兴趣的朋友可以看看。

ActionBarContainer的视图属性,如下图所示:

actionbar_container.png
  • ActionBarContainer从名字也可以看出这是一个标题栏容器。
  • ActionBarContainer的子View中当前处于显示状态的只有一个Toolbar。

视图部分分析到这基本上就OK了,笔者就不再向下分析了。只要读者能学会这个工具的使用方法,基本上就可以自己尝试分析了。

不过,还有个问题需要提醒一下,不同机型,不同系统主题设置生成的视图结构可能会不一样,举两个例子:

例一:笔者把使用的模拟器换成自己的手机(360N5 Android 6.0.1),运行后视图布局如下:

360N5.png

可以看到笔者的手机是没有NavigationBar(底部导航栏)的

例二:笔者把Activity的主题"Theme.AppCompat.Light.DarkActionBar"换成无标题栏主题"Theme.AppCompat.Light.NoActionBar",运行后视图布局如下:

change_theme.png

可以看到视图结构与我们之前分析的相比,发生了一些变化。

2017.09.08 问题反馈:
最近有读者反馈AndroidStudio在调试App页面时,会偶发Layout Inspector按钮为灰色,无法打开的问题,如下图所示:


layout_inspector_error.png

这可能是AndroidStudio快捷打开方式的一个Bug,遇到这个问题可以去菜单栏打开Layout Inspector,打开位置如下:


layout_inspector_open.png

最后,还有个细节给各位补充下:Layout Inspector 只能分析出Android Studio当前“正在运行的APP”的视图布局结构,其他应用的视图布局结构是无法显示的。

如果我们想要分析一个第三方应用(如:微信、QQ)的视图结构可以使用Android Device Monitor(安卓设备监视器),具体打开步骤如下图所示:

android_device_monitor.png

以QQ为例,我们先打开手机QQ,显示出QQ主界面,然后按照下图的"红色圈选",依次点击,当前的视图结构就出来了,但是相比于Layout Inspector工具,视图属性信息提供的较少...

qq_layout.png

视图层级分析到此结束,有时间再补篇源码,分析一下布局加载的流程。

题外话

写这篇文章的时候被IOS同事嘲讽了,它们吐槽Android的视图分析工具太渣,最后对比看了下,Android的视图分析工具确实没有IOS的高大上......╮(╯▽╰)╭

最后,秀一下IOS的视图分析工具Reveal,如下图所示:

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

推荐阅读更多精彩内容