Android進階 - 視圖層級實時分析

android_7.1.png

摘要

在App運行過程中,我們的視圖層級可能會由于用戶的操作一直在發(fā)生改變,甚至可能會有一些出乎預(yù)料的變化,本文將會介紹如何進行Android視圖實時分析,分析View的視圖層級及屬性變化。

引題

注:
1.筆者分析代碼使用的API版本為API 25 (Android 7.1)
2.筆者使用的模擬器為Android 7.1

首先,筆者先來一個簡單的Demo實例。我們使用Android Studio新建一個Empty Android工程,跑一下程序,界面如下圖所示:

activity.png

接下來,我們要對視圖層級進行分析,但分析之前先給各位介紹兩個視圖分析工具。

1.Android SDKtools包下的hierarchyviewer,最終展現(xiàn)的視圖效果如下:

hierarchyviewer.png

2.Android Studio也有自帶的視圖分析工具 Layout Inspector(布局檢查器),打開方式如下圖所示:

layout_inspector.png

可以看到Layout Inspector最右側(cè)的屬性欄可以查看每一個View的所附帶的屬性及屬性值。

注:筆者推薦Android Studio開發(fā)者可以使用Layout Inspector。

正文

一.視圖層級分析

從根視圖開始分析視圖層級,如下圖所示:

decorview.png
  • 我們可以看到視圖的根布局是DecorView,寬度和高度為模擬器屏幕寬高。
  • DecorView中包含3個子View:LinearLayout、View、View。

DecorView的第一個子View(LinearLayout), 如下圖所示:

linearlayout.png
  • LinearLayout的高度與屏幕高度相比少了96像素,從layout_bottomMargin屬性可以知道這96像素用來預(yù)留底部邊界了。

DecorView的第二個子View(View),如下圖所示:

navigationbar.png
  • View的ID值表明了這個視圖的作用:底部導(dǎo)航欄背景
  • 這個View的高度是96像素(屬性列表間距較大,截圖沒有截到)

DecorView的第三個子View(View),如下圖所示:

statusbar.png
  • View的ID值表明了這個視圖的作用:狀態(tài)欄背景
  • 這個View的高度是48像素(屬性列表間距較大,截圖沒有截到)

插入一點劇情:
有朋友可能會問,是不是只要知道這個ID值(statusBarBackground),我們就可以拿到這個狀態(tài)欄背景View,之后想怎么操作這個View都可以?

答案:可以。但這里有一些注意點:

  • 只有在API 21(Android 5.0)以上才能獲取到該"狀態(tài)欄View",如下圖所示:


    get_statusbar.png
  • 在onCreate方法里直接獲取該"狀態(tài)欄View"值為null,如下圖所示:


    get_statusbar_fail.png
  • 當(dāng)視圖已經(jīng)顯示出來時,可以拿到這個"狀態(tài)欄View",如下圖所示:


    get_statusbar_success.png
  • 簡單說明一下在onCreate方法里直接獲取"狀態(tài)欄View"值為null的原因:
    findViewById(int id) 這個方法最終會走的DecorView(ViewGroup)的findViewTraversal(int id)方法進行View遍歷,根據(jù)id值查找子View。我們Debug走到這個方法時發(fā)現(xiàn)DecorView里只有一個LinearLayout,另外兩個View還沒有加載進來,如下圖所示:
    statusbar_reason.png

    結(jié)論:當(dāng)我們在OnCreate方法里執(zhí)行完setContentView(int id)方法后,"狀態(tài)欄View"和"底部導(dǎo)航欄View"還沒有添加進DecorView,此時生成的DecorView并不是最終顯示的DecorView。

至此,DecorView的最外層View全部分析完畢。


接下來,分析DecorView的第一個子View(LinearLayout),如下圖所示:

linearlayout_detail.png
  • LinearLayout包含兩個子View:ViewStub和FrameLayout
  • ViewStub顯示的文字顏色為灰色,說明該View沒有在當(dāng)前視圖上顯示出來。

注:ViewStub繼承自View,是一種視圖容器,一般用于對布局資源的加載流程進行優(yōu)化。

ViewStub的屬性信息,如下圖所示:

viewstub.png
  • ViewStub的getVisibility屬性值為 GONE (ViewStub處于隱藏狀態(tài))

FrameLayout的屬性信息,如下圖所示:

framelayout.png
  • FrameLayout的高度值為1136px,相比于父布局LinearLayout又少了48px。
  • 從mTop屬性可以知道,F(xiàn)rameLayout在布局時頂點坐標(biāo)高度從48px開始,空出了狀態(tài)欄的高度。

接下來,繼續(xù)分析FrameLayout的子View,如下圖所示:

actionbaroverlaylayout.png
  • FrameLayout只有一個子View:ActionBarOverlayLayout
  • ActionBarOverlayLayout的寬度和高度與FrameLayout保持一致。
  • ActionBarOverlayLayout有兩個子View:ContentFrameLayout和ActionBarContainer

ContentFrameLayout的視圖屬性,如下圖所示:

content_framelayout.png
  • ContentFrameLayout的高度相比于父布局減少了112px
  • 從layout_topMargin屬性可以看出,這112px用于預(yù)留頂部邊界,空出了標(biāo)題欄的高度。
content_framelayout2.png
  • ContentFrameLayout的mID屬性值為content(android.R.id.content)
  • ContentFrameLayout里的子View就是我們activity_main.xml中的視圖了。

注:這里有個很有趣的地方,我們activity_main.xml文件里用的是TextView,但是最后卻被轉(zhuǎn)成了AppCompatTextView。限于篇幅,筆者重起了一篇文章Android進階 - 源碼中的視圖轉(zhuǎn)換,有興趣的朋友可以看看。

ActionBarContainer的視圖屬性,如下圖所示:

actionbar_container.png
  • ActionBarContainer從名字也可以看出這是一個標(biāo)題欄容器。
  • ActionBarContainer的子View中當(dāng)前處于顯示狀態(tài)的只有一個Toolbar。

視圖部分分析到這基本上就OK了,筆者就不再向下分析了。只要讀者能學(xué)會這個工具的使用方法,基本上就可以自己嘗試分析了。

不過,還有個問題需要提醒一下,不同機型,不同系統(tǒng)主題設(shè)置生成的視圖結(jié)構(gòu)可能會不一樣,舉兩個例子:

例一:筆者把使用的模擬器換成自己的手機(360N5 Android 6.0.1),運行后視圖布局如下:

360N5.png

可以看到筆者的手機是沒有NavigationBar(底部導(dǎo)航欄)的。

例二:筆者把Activity的主題"Theme.AppCompat.Light.DarkActionBar"換成無標(biāo)題欄主題"Theme.AppCompat.Light.NoActionBar",運行后視圖布局如下:

change_theme.png

可以看到視圖結(jié)構(gòu)與我們之前分析的相比,發(fā)生了一些變化。

2017.09.08 問題反饋:
最近有讀者反饋AndroidStudio在調(diào)試App頁面時,會偶發(fā)Layout Inspector按鈕為灰色,無法打開的問題,如下圖所示:


layout_inspector_error.png

這可能是AndroidStudio快捷打開方式的一個Bug,遇到這個問題可以去菜單欄打開Layout Inspector,打開位置如下:


layout_inspector_open.png

最后,還有個細節(jié)給各位補充下:Layout Inspector 只能分析出Android Studio當(dāng)前“正在運行的APP”的視圖布局結(jié)構(gòu),其他應(yīng)用的視圖布局結(jié)構(gòu)是無法顯示的。

如果我們想要分析一個第三方應(yīng)用(如:微信、QQ)的視圖結(jié)構(gòu)可以使用Android Device Monitor(安卓設(shè)備監(jiān)視器),具體打開步驟如下圖所示:

android_device_monitor.png

以QQ為例,我們先打開手機QQ,顯示出QQ主界面,然后按照下圖的"紅色圈選",依次點擊,當(dāng)前的視圖結(jié)構(gòu)就出來了,但是相比于Layout Inspector工具,視圖屬性信息提供的較少...

qq_layout.png

視圖層級分析到此結(jié)束,有時間再補篇源碼,分析一下布局加載的流程。

題外話

寫這篇文章的時候被IOS同事嘲諷了,它們吐槽Android的視圖分析工具太渣,最后對比看了下,Android的視圖分析工具確實沒有IOS的高大上......╮(╯▽╰)╭

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

reveal.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容