Android面試一天一題(Day 42:關于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來布局的話,它可以適應各種界面的改變(所以叫響應式布局)。

看一下官方圖片感受一下:


如果對前端的Flexbox不太了解的話,你還需要補一些概念,好在這些東西在網上很容易找到。

小結

可能很多讀者會覺這樣的面試題是吹毛求疵,很多項目中哪有這么復雜的界面,根本就用不到這些優化措施。

So,你沒有成長為厲害的人。

可以說厲害的人,或者叫高手,可能只是比較多在意這些細節而已。在實踐中的經歷告訴我,很多難于解決的性能問題,并不是因為有一個影響性能的問題無法攻克,而是沒有一個明顯的制約因素,是有各種小問題一點一點堆積起來,最終積重難返。

所以,把細節做好,或者意識到細節的地方可能引發的問題,對我們解決問題是很有幫助的,不要浪費了讓你可以成長的細節。


相關閱讀:

Android面試一天一題(Day 37:一套高級工程師的面試題)
Android面試一天一題(Day 30:老外的自定義View面試題)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容