1、ConstraintLayout是什么?
廢話,當然是布局類型了。以前的布局類型有5種:線性布局、幀布局、相對布局、表格布局、絕對布局,常用的其實也就是前面三種。
ConstraintLayout就是約束布局,就是根據控件與控件之間的約束條件來決定最后在界面上的位置。就好像拼圖一樣,每一塊拼圖都跟相鄰的拼圖有約束關系,而拼圖的邊和角就直接和相框有約束關系,從而最后組成一幅完整的圖畫。
2、為什么需要ConstraintLayout?
了解過或者做過布局優化的話,應該都了解,如果布局內的層數越多,越消耗性能。可以看到,要繪制一個界面,就需要在樹里面先找到葉子,確定好了葉子的大小和位置,再逐步向上遍歷。簡單的,也就是遞歸。所以當布局內的層數越多,那布局的計算也就越復雜。
而ConstraintLayout,就是讓所有的布局內的view,都平鋪在同一層,從而減少布局內的層數,優化界面的繪制消耗。
3、relativeLayout也可以達到單層布局,ConstraintLayout真的有用?
來試一試,先自定義2個View,分別繼承relativeLayout和ConstraintLayout,并統計onMeasure的時間。
<?xml version="1.0" encoding="utf-8"?>
<com.example.test.view.MeasureTimeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
</com.example.test.view.MeasureTimeRelativeLayout>
這是相對布局的xml文件,我們多次啟動,看看界面繪制的耗時:
那再看看ConstraintLayout的耗時:
4、如果層次多一點的界面,耗時怎么樣?
<?xml version="1.0" encoding="utf-8"?>
<com.example.test.view.MeasureTimeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rl1"
android:layout_width="match_parent"
android:layout_height="300dp">
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/textView2"
android:layout_centerHorizontal="true">
<TextView
..../>
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="@id/rl1">
<TextView
..../>
<TextView
..../>
<TextView
... />
<TextView
... />
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/textView22"
android:layout_centerHorizontal="true">
<TextView
..../>
</RelativeLayout>
</RelativeLayout>
</com.example.test.view.MeasureTimeRelativeLayout>
這是RelativeLayout的耗時:那我們為什么還要用ConstraintLayout?
其實,上面的情況是這樣,只是因為布局內的元素還算是簡單的搭配,但是隨著界面的復雜度提升,還有一些view的計算,這時候ConstraintLayout的性能優勢就體現出來了。
例如以下幾個例子:
①根據中心view,其他view按照角度來定位布局。
后兩種已經是常見得不能再常見的需求了,但是如果不使用ConstraintLayout,只使用相對布局或者線性布局來實現,那就只能動態獲取相應的文字寬度、圖片的大小比例,之后再去計算填充到布局里了。
ConstraintLayout還有很多強大的屬性,是其他布局做不到或者很難做到的,感興趣的可以自行搜索研究。
那ConstraintLayout是怎么做到復雜的布局的性能優化的?
ConstraintLayout 的組成可以大致分為三個部分:ConstraintWidgetContainer,ConstraintWidget 和 Cassowary 算法(全稱 The Cassowary Linear Arithmetic Constraint Solving Algorithm,有興趣的同學可以自行搜索)。
ConstraintWidgetContainer 相當于引擎,ConstraintWidget 是所有 ConstraintLayout 所包含控件的抽象(每個child 對應一個 ConstraintWidget),ConstraintWidgetContainer 驅動 所有 ConstraintWidget 進入 Cassowary算法封裝盒子,Cassowary 將計算好的 ConstraintWidget 輸出交給 ConstraintWidgetContainer,這時,所有child 的布局數據都已經被計算出來,ConstraintLayout只需要把它們放在數據指示的位置即可。
還記得上面實驗計算耗時的結果嗎?ConstraintLayout的耗時隨著進入界面的次數,是逐步減少的,為什么會這樣?
其實這個不是ConstraintLayout干的優化結果,是Android的機制問題。
Android 2.2-4.4:
這部分都是使用JIT,就是說都是在運行的時候,需要用什么,就加載什么,好處就是安裝賊快,但缺點也明顯,每次運行都需要重新編譯,浪費資源,例如電量。
Android L(5.0)- Android N:
安裝時直接使用預先編譯(AOT),就是把所有代碼一次性轉化為本地機器碼,當需要使用時就可以直接使用了。但是缺點就是第一次安裝的時候十分的慢,因為一次性轉化全部代碼很耗時。
Android N(7.0)以上的:
安裝apk的時候,不進行任何的預編譯(提高安裝速度);
運行的過程中解析執行,并且對經常使用的方法進行優化,就是即時編譯(JIT just in time),經過JIT處理的代碼,都會記錄在一個profile配置文件里;
最后在手機閑的時候,有一個編譯守護進程,會對profile里面的方法進行預先編譯(AOT),把這些代碼轉化為本地機器碼。
是由于這個原因,使得ConstraintLayout的耗時越來越少的。如果拿幾臺對應的系統版本手機來測試,你就會發現5.0-N的是耗時最少的,而且耗時不變。而另外2種,耗時都是逐漸減少。
那ConstraintLayout有啥缺點?
純個人觀點:
①要多寫點屬性
②牽一發而動全身,有時候改一個控件,布局全變了(所以一定要找好作為錨的控件)
③如果界面布局不是很復雜,性能甚至比舊的布局類型還要差
④復雜的界面,所用元素都放在統一平面上,代碼的可讀性會十分差
總結:
①不要一股腦全用ConstraintLayout,簡單的布局,還是其他布局類型較好。
②網上一堆說ConstraintLayout的性能優化,都好像只是說布局的嵌套層數問題,其實并不是,需要看實際情況。
③就算ConstraintLayout能做到全部元素放在統一父布局內,也應該適當地分層