Android面試集錦系列(4)——關於Android佈局你不知道的
Android常見的5個佈局,我想大家一定不會陌生。LinearLayout、RelativeLayout和FrameLayout也是使用頻率較高的佈局方式,做Android開發的一定使用過。
傳統的5種佈局方式:
- LinearLayout
- RelativeLayout
- FrameLayout
- GridLayout
- TableLayout
不過我的問題並不是問面試者如何使用這些基礎的佈局,而是要看面試者怎麼解決佈局巢狀(影響效能)和螢幕適配問題。
面試題:你是如何解決Android的佈局巢狀問題的?
我們都清楚Android介面的佈局太複雜,巢狀層次過深,會使整個介面的測量、佈局和繪製變得更復雜,對效能會造成影響。所以我們在寫Layout檔案時,也要儘量避免佈局的巢狀層次過深的問題。
在怎麼解決問題之前,我們得有一個好方法先判斷當前的問題情況。Android SDK工具箱中有一個叫做Hierarchy Viewer的工具,能夠在App執行時分析Layout。
注意:在ROOT的手機,或者是安裝開發版的ROM的手機可以直接使用Hierarchy Viewer。
如果沒有Root的手機(SDK 4.1及以上),需要在你的PC端新增一個環境變數“ANDROID_HVPROTO=ddm”。
Mac系統的配置如下:

儲存後執行:source ~/.bash_profile
最後可以DDMS的Hierarchy Viewer看到:

下面列舉一些面試者常使用的方式。
merge
merge標籤的作用是合併UI佈局,使用該標籤能降低UI佈局的巢狀層次。
merge標籤可用於兩種情況:
- 佈局頂結點是FrameLayout且不需要設定background或padding等屬性,可以用merge代替,因為Activity內容試圖的parent view就是個FrameLayout,所以可以用merge消除只剩一個。
- 某佈局作為子佈局被其他佈局include時,使用merge當作該佈局的頂節點,這樣在被引入時頂結點會自動被忽略,而將其子節點全部合併到主佈局中。
ViewStub
ViewStub標籤引入的佈局預設不會inflate,既不會顯示也不會佔用位置。 ViewStub常用來引入那些預設不會顯示,只在特殊情況下顯示的佈局,如資料載入進度佈局、出錯提示佈局等。
需要在使用時手動inflate:
ViewStub stub = (ViewStub)findViewById(R.id.error_layout); errorView = stub.inflate(); errorView.setVisibility(View.VISIBLE);
ViewStub在一定的程度可以起到減少巢狀層次的作用,特別是很多時候我們的程式可能不需要走到ViewStub的介面。
include
將可複用的元件抽取出來並通過include標籤使用,但<include>標籤能減少佈局的層次嗎?
我認為不能。include主要解決的是相同佈局的複用問題,它並不能減少佈局的層次。
用RelativeLayout代替LinearLayout
很多人為了減少佈局層次喜歡用RelativeLayout代替LinearLayout,不過可能達到的效果並不會很明顯。層次是減少了,但本身RelativeLayout就會比LinearLayout效能差一點。
有一些介面,比如一個圖片和一個文字的佈局(ListItem常見的佈局方式),可以利用TextView有drawableLeft, drawableRight等屬性,完全不需要RelativeLayout或者LinearLayout佈局。
你不知道的兩種新的佈局方式
傳統的佈局方式存在一定的缺陷,如RelativeLayout要兩次測量(measure)它的子View才能知道確切的高度;如果LinearLayout佈局的子View有設定了layout_weight,那麼它也需要測量兩次才能獲得佈局的高度。
相對於傳統的佈局方式,Android官方還推出了兩種新的佈局方式:ConstraintLayout和FlexboxLayout。
ConstraintLayout
ConstraintLayout即約束佈局,在2016年由Google I/O推出。ConstraintLayout和RelativeLayout有點類似,控制元件之間根據依賴關係而存在,但比RelativeLayout更加靈活。建立大型複雜的佈局仍然可以使用扁平的層級(不用巢狀View Group),說的簡單些就是,再複雜的介面也可以只有2層層次。
要使用ConstraintLayout需要在build.gradle中新增相關的support庫:
compile 'com.android.support.constraint:constraint-layout:1.0.2'
Android Studio 2.3及之後的版本使用引導建立Empty的Activity時,預設就是使用ConstraintLayout佈局。關於本面試題的答案,官方其實已經明確給出訊號了。

使用ConstraintLayout可以有效的解決佈局巢狀過多導致的效能問題,官方也對其渲染效能進行了優化,並且ConstraintLayout支援視覺化的方式編寫佈局。
不過學會熟練使用ConstraintLayout會需要一點時間,但這是值得的。
官方文件: https://developer.android.com/training/constraint-layout/index.html
FlexBoxLayout
做過前端開發(CSS方面)的同學對FlexBox一定不會陌生,最近我在做微信小程式開發時也涉及到FlexBox。FlexBox(彈性佈局)是w3c在2009年提出的一種新的佈局方案,解決以前那種傳統css的盒模型的侷限性。
Google開源了FlexboxLayout佈局和前端CSS FlexBox佈局具有相同的功能(肯定有不一樣的地方),但已經足夠在Android上改進佈局的構建方式。
專案地址: https://github.com/google/flexbox-layout
FlexBoxLayout可以理解成一種更高階的LinearLayout,不過比LinearLayout更加強大和靈活。如果我們使用LinearLayout佈局的話,那麼不同的解析度,也許我們要重新調整佈局,勢必會需要跟多的佈局檔案放在不同的資源目錄。而使用FlexBoxLayout來佈局的話,它可以適應各種介面的改變(所以叫響應式佈局)。
看一下官方圖片感受一下:
[圖片上傳失敗...(image-400cc5-1551951308408)]
如果對前端的Flexbox不太瞭解的話,你還需要補一些概念,好在這些東西在網上很容易找到。
小結
可能很多讀者會覺這樣的面試題是吹毛求疵,很多專案中哪有這麼複雜的介面,根本就用不到這些優化措施。
So,你沒有成長為厲害的人。
可以說厲害的人,或者叫高手,可能只是比較多在意這些細節而已。在實踐中的經歷告訴我,很多難於解決的效能問題,並不是因為有一個影響效能的問題無法攻克,而是沒有一個明顯的制約因素,是有各種小問題一點一點堆積起來,最終積重難返。
所以,把細節做好,或者意識到細節的地方可能引發的問題,對我們解決問題是很有幫助的,不要浪費了讓你可以成長的細節。
最後
針對於上面的面試題我總結出了網際網路公司Android程式設計師面試涉及到的絕大部分面試題及答案做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】: 加入群聊

資料大全