ConstraintLayout優缺點,真的能提升性能?

1、ConstraintLayout是什么?

廢話,當然是布局類型了。以前的布局類型有5種:線性布局、幀布局、相對布局、表格布局、絕對布局,常用的其實也就是前面三種。
ConstraintLayout就是約束布局,就是根據控件與控件之間的約束條件來決定最后在界面上的位置。就好像拼圖一樣,每一塊拼圖都跟相鄰的拼圖有約束關系,而拼圖的邊和角就直接和相框有約束關系,從而最后組成一幅完整的圖畫。

2、為什么需要ConstraintLayout?

了解過或者做過布局優化的話,應該都了解,如果布局內的層數越多,越消耗性能。
image.png

可以看到,要繪制一個界面,就需要在樹里面先找到葉子,確定好了葉子的大小和位置,再逐步向上遍歷。簡單的,也就是遞歸。所以當布局內的層數越多,那布局的計算也就越復雜。
而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文件,我們多次啟動,看看界面繪制的耗時:

image.png
每次進入界面,會觸發2次onMeasure,可以看到,第一次測量的耗時,大概是3毫秒左右。
那再看看ConstraintLayout的耗時:
image.png
可以看到,耗時立馬不對勁了起來,比RelativeLayout耗時多太多了,但是如果有留意到的話,你會發現,耗時是越來越少的,當進入界面的次數越來越多,界面測量的耗時就和RelativeLayout差不多一樣了。為什么這樣,稍后再研究。

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的耗時:
image.png

這是ConstraintLayout的耗時:
image.png
google官網所說的性能優化,就這?看起來還不如RelativeLayout啊。
那我們為什么還要用ConstraintLayout?

其實,上面的情況是這樣,只是因為布局內的元素還算是簡單的搭配,但是隨著界面的復雜度提升,還有一些view的計算,這時候ConstraintLayout的性能優勢就體現出來了。
例如以下幾個例子:
①根據中心view,其他view按照角度來定位布局。

image.png
②同一水平方向,多個view排列,中間的view長度變化不影響邊緣view的顯示
image.png
③圖片按照一定比例顯示

后兩種已經是常見得不能再常見的需求了,但是如果不使用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能做到全部元素放在統一父布局內,也應該適當地分層

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

推薦閱讀更多精彩內容