欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Androd 勇闖高階性能優(yōu)化之布局優(yōu)化篇

 更新時間:2021年10月23日 10:52:37   作者:帥次  
Android性能優(yōu)化方面也有很多文章了,這里就做一個總結(jié),從原理到方法,工具等做一個簡單的了解,從而可以慢慢地改變編碼風(fēng)格,從而提高性能

Android的布局管理器本身就是個UI組件,所有的布局管理器都是ViewGroup的子類,而ViewGroup是View的子類,所以布局管理器可以當(dāng)成普通的UI組件使用,也可以作為容器類使用,可以調(diào)用多個重載addView()向布局管理器中添加組件,并且布局管理器可以互相嵌套,當(dāng)然不推薦過多的嵌套 (如果要兼容低端機型,最好不要超過5層)。

🔥 布局層級管理

讓咱們一起了解一下每當(dāng)系統(tǒng)繪制一個布局時,都會發(fā)生一些什么。這一過程由兩個步驟完成:

💥 繪制(Measurement)

  • 1:根布局測量自身。
  • 2:根布局要求它內(nèi)部所有子組件測量自身。
  • 3:所有自布局都需要讓它們內(nèi)部的子組件完成這樣的操作,直到遍歷完視圖層級中所有的View。

💥 擺放(Positioning)

  • 1:當(dāng)布局中所有的View都完成了測量,根布局則開始將它們擺放到合適的位置。
  • 2:所有子布局都需要做相同的事情,直到遍歷完視圖層級中所有的View。

💥 背景設(shè)置產(chǎn)生的過度繪制

  • 組件背景:每個組件每設(shè)置一次背景, 該組件的區(qū)域就會增加一層繪制 , 如 LinearLayout 設(shè)置背景顏色 , 里面的 TextView 設(shè)置背景顏色 , 都會增加該組件區(qū)域內(nèi)的過渡繪制 ;
  • 主題背景:Activity 界面的主題背景,會增加一次 GPU 繪制 ;

不要隨意給布局中的 UI 組件設(shè)置背景 。如 ImageView 設(shè)置一張圖片,會增加一次繪制 ,再給該 ImageView 組件設(shè)置背景顏色, 那么又會增加一次繪制, 那么該 ImageView 組件肯定過渡繪制了。

💥 小結(jié)

當(dāng)某個View的屬性發(fā)生變化(如:TextView內(nèi)容變化或ImageView圖像發(fā)生變化),View自身會調(diào)用View.invalidate()方法(必須從 UI 線程調(diào)用),自底向上傳播該請求,直到根布局(根布局會計算出需要重繪的區(qū)域,進(jìn)而對整個布局層級中需要重繪的部分進(jìn)行重繪)。布局層級越復(fù)雜,UI加載的速度就越慢。因此,在編寫布局的時候,盡可能地扁平化是非常重要的。

FrameLayout和TableLayout有各自的特殊用途,LinearLayout 和 RelativeLayout 是可以互換的,ConstraintLayout和RelativeLayout類似。也就是說,在編寫布局時,可以選擇其中一種,咱們可以以不同的方式來編寫下面這個簡單的布局。

🔥 小實驗(多種方式實現(xiàn)同一布局)

💥 LinearLayout

第一種方式是使用LinearLayout,雖然可讀性比較強,但是性能比較差。由于嵌套LinearLayout會加深視圖層級,每次擺放子組件時,相對需要消耗更多的計算。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <View
        android:id="@+id/view_top_1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/color_666666"/>
    <View
        android:id="@+id/view_top_2"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@color/teal_200"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <View
            android:id="@+id/view_top_3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/color_FF773D"/>
        <View
            android:id="@+id/view_top_4"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/purple_500"/>
    </LinearLayout>
</LinearLayout>

LinearLayout視圖層級如下所示:

💥 使用RelativeLayout

第二種方法使用RelativeLayout,在這種情況下,你不需要嵌套其他ViewGroup,因為每個子View可以相當(dāng)于其他View,或相對與父控件進(jìn)行擺放。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <View
        android:id="@+id/view_top_1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/color_666666"/>
    <View
        android:id="@+id/view_top_2"
        android:layout_width="200dp"
        android:layout_below="@id/view_top_1"
        android:layout_height="100dp"
        android:background="@color/teal_200"/>
    <View
        android:id="@+id/view_top_3"
        android:layout_width="100dp"
        android:layout_below="@id/view_top_2"
        android:layout_height="100dp"
        android:background="@color/color_FF773D"/>
    <View
        android:id="@+id/view_top_4"
        android:layout_width="100dp"
        android:layout_below="@id/view_top_2"
        android:layout_toRightOf="@id/view_top_3"
        android:layout_height="100dp"
        android:background="@color/purple_500"/>
</RelativeLayout>

RelativeLayout視圖層級如下所示:

通過兩種方式,可以很容易看出,第一種方式LinearLayout需要3個視圖層級和6個View,第二種方式RelativeLayout僅需要2個視圖層級和5個View。

當(dāng)然,雖然RelativeLayout效率更高,但不是所有情況都能通過相對布局的方式來完成控件擺放。所以通常情況下,這兩種方式需要配合使用。

注意:為了保證應(yīng)用程序的性能,在創(chuàng)建布局時,需要盡量避免重繪,布局層級應(yīng)盡可能地扁平化,這樣當(dāng)View被重繪時,可以減少系統(tǒng)花費的時間。在條件允許的情況下,盡量的使用RelativeLayout和ConstraintLayout,而非LinearLayout,或者用GridLayoutl來替換LinearLayout。

咱們最常使用的是ViewGroup是LinearLayout,只是因為它很容易看懂,編寫起來簡單,所以它就成了Android開發(fā)的首選。出于這個原因,Google推出了一個全新的ViewGroup。在適當(dāng)?shù)臅r候時候使用它,可以減少冗余,它就是網(wǎng)格布局GridLayout下。

🔥 布局復(fù)用(<include/>和 <merge/> )

Android 提供了一個非常有用的標(biāo)簽。在某些情況下,當(dāng)你希望在其他布局中用一些已存在的布局時, 標(biāo)簽可通過制定相關(guān)引用ID,將一個布局添加到另一個布局。

比如自定義一個標(biāo)題欄,那么可以按照下面的方式,創(chuàng)建一個可重復(fù)用的布局文件。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <View
        android:id="@+id/view_top_1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/color_666666"/>
</RelativeLayout>

接著,將標(biāo)簽放入相應(yīng)的布局文件中,替換掉對應(yīng)的 View:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include layout="@layout/include_layout"/>
    ...
</RelativeLayout>

這么一來,當(dāng)你希望重用某些View時,就不用復(fù)制/粘貼的方式來實現(xiàn),只需要定義一個layout文件,然后通過 引用即可。

但是這樣做,可能會引入一個冗余的ViewGroup(重用的布局文件的根視圖)。為此,Android 提供了另一個標(biāo)簽,用來幫我們減少布局冗余,讓層級變得更加扁平化。我們只需要將可重用的根視圖,替換為 標(biāo)簽即可。如下所示:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <View
        android:id="@+id/view_top_1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/color_666666"/>
</merge>

如此一來,就沒有了冗余的視圖控件,因為系統(tǒng)會忽略標(biāo)簽,并將標(biāo)簽中的視圖直接放置在相應(yīng)的布局文件中,替換標(biāo)簽。

注意:使用此標(biāo)簽時,需要記住它的兩個主要限制:

1、它只能作為布局文件的跟來使用。

2、每次調(diào)用LayoutInflater.inflate()時,必須為布局文件提供一個View,作為它的父容器:LayoutInflater.from(this).inflate(R.layout.merge_layout,parent,true);

🔥 ViewStub

ViewStub是一個不可見的零大小View,可以作為一個節(jié)點被加入布局文件,但他關(guān)聯(lián)的布局,知道運行時通過調(diào)用 ViewStub.inflate() 或 View.setVisibility(View.VISIBLE) 方法,才會被繪制。

先看效果圖:

💥 ViewStub 設(shè)置

        <ViewStub android:id="@+id/viewStub"
            android:inflatedId="@+id/subTree"
            android:layout="@layout/activity_imageview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

💥 顯示

上方 ViewStub 所關(guān)聯(lián)的布局 activity_imageview 并不會被實例化(不要調(diào)用布局內(nèi)的控件,因為還沒加載會報空指針異常),只有程序在運行期間調(diào)用了以下方法:

findViewById(R.id.viewStub).setVisibility(View.VISIBLE);
 
((ViewStub)findViewById(R.id.viewStub)).inflate();

在這期間不要調(diào)用關(guān)聯(lián)布局內(nèi)的控件,因為還沒唄加載沒有

一旦 ViewStub 變成 visible 或者被 inflate,它便不再可用(Id:viewStub沒了),因為它在布局層級中的位置已經(jīng)實例化出來的布局所替代,因為不能被訪問,而應(yīng)該使用 android:inflatedId 屬性中的ID。如下:

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_view:
                break;
            case R.id.btn_scheme:
                //加載,選擇一種即可。
                findViewById(R.id.v_stud).setVisibility(View.VISIBLE);
                //((ViewStub)findViewById(R.id.v_stud)).inflate();
 
                //加載后layout所用ID
                subTree  = findViewById(R.id.subTree);
                findViewById(R.id.btn_iv_basis).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this,"我是 ViewStud 加載的控件",Toast.LENGTH_SHORT).show();
                    }
                });
                break;
            case R.id.btn_invisible:
                subTree.setVisibility(View.INVISIBLE);
                break;
            case R.id.btn_visible:
                subTree.setVisibility(View.VISIBLE);
                break;
            case R.id.btn_init:
                //ViewStub變?yōu)榭梢姾笤俅握{(diào)用會報空指針,因為id:viewStub 已經(jīng)不存在了。
                View viewStub  = findViewById(R.id.viewStub);
                viewStub.setVisibility(View.GONE);
                break;
        }
    }

💥 小結(jié)

ViewStub 非常有用,我們可以通過 ViewStub 來延遲部分 View 的加載,縮短首次加載時間,以及減少一些不必要的內(nèi)存分配。

🔥 自定義組件優(yōu)化

在自定義View時需要注意,避免犯以下的性能錯誤:

  • 在非必要時,對View進(jìn)行重繪。
  • 繪制一些不被用戶所看到的的像素,也就是過度繪制。(被覆蓋的地方)
  • 在繪制期間做了一些非必要的操作,導(dǎo)致內(nèi)存資源的消耗。

💥 優(yōu)化

  • View.invalite()是最最廣泛的使用操作,因為在任何時候都是刷新和更新視圖最快的方式。

在自定義View時要小心避免調(diào)用非必要的方法,因為這樣會導(dǎo)致重復(fù)強行繪制整個視圖層級,消耗寶貴的幀繪制周期。檢查清楚View.invalite()和View.requestLayout()方法調(diào)用時間位置,因為這會影響整個UI,導(dǎo)致GPU和它的幀速率變慢。

  • 避免過渡重繪。為了避免過渡重繪,我們可以利用Canvas方法,只繪制控件中所需要的部分。整個一般在重疊部分或控件時特別有用。相應(yīng)的方法是Canvas.clipRect()(指定要被繪制的區(qū)域);
  • 在實現(xiàn)View.onDraw()方法中,不應(yīng)該在方法內(nèi)及調(diào)用的方法中進(jìn)行任何的對象分配。在該方法中進(jìn)行對象分配,對象會被創(chuàng)建和初始化。而當(dāng)View.onDraw()方法執(zhí)行完畢時。垃圾回收器會釋放內(nèi)存。如果View帶動畫,那么View在一秒內(nèi)會被重繪60次。所以要避免在View.onDraw()方法中分配內(nèi)存。

永遠(yuǎn)不要在View.onDraw()方法中及調(diào)用的方法中進(jìn)行內(nèi)存分配,避免帶來負(fù)擔(dān)。垃圾回收器多次釋放內(nèi)存,會導(dǎo)致卡頓。最好的方式就是在View被首次創(chuàng)建出來時,實例化這些對象。

布局優(yōu)化到這里就結(jié)束了,還是那句話后面如果有更好的方案會及時的添加進(jìn)去,如果有老大有其他方案也可以留言哈,感謝!

到此這篇關(guān)于Androd 勇闖高階性能優(yōu)化之布局優(yōu)化篇的文章就介紹到這了,更多相關(guān)Android 布局優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android Zxing 轉(zhuǎn)換豎屏掃描且提高識別率的方法

    Android Zxing 轉(zhuǎn)換豎屏掃描且提高識別率的方法

    本篇文章主要介紹了Android Zxing 轉(zhuǎn)換豎屏掃描且提高識別率的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Android簡易音樂播放器實現(xiàn)代碼

    Android簡易音樂播放器實現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android簡易音樂播放器的實現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Android實現(xiàn)微信朋友圈發(fā)本地視頻功能

    Android實現(xiàn)微信朋友圈發(fā)本地視頻功能

    這篇文章主要介紹了Android實現(xiàn)微信朋友圈發(fā)本地視頻功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-11-11
  • android ViewPager實現(xiàn)自動無限輪播和下方向?qū)A點

    android ViewPager實現(xiàn)自動無限輪播和下方向?qū)A點

    本篇文章主要介紹了android ViewPager實現(xiàn)自動輪播和下方向?qū)A點,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • Android Studio IDE升級4.1以后Start Failed

    Android Studio IDE升級4.1以后Start Failed

    這篇文章主要介紹了Android Studio IDE升級4.1以后Start Failed,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Kotlin?this關(guān)鍵字的使用實例詳解

    Kotlin?this關(guān)鍵字的使用實例詳解

    這篇文章主要介紹了Kotlin?this關(guān)鍵字的使用實例,在Kotlin中,this關(guān)鍵字允許我們引用一個類的實例,該類的函數(shù)恰好正在運行。此外,還有其他方式可以使this表達(dá)式派上用場
    2023-02-02
  • 基于VideoView自定義控制面板的視頻播放器

    基于VideoView自定義控制面板的視頻播放器

    這篇文章主要為大家詳細(xì)介紹了基于VideoView自定義控制面板的視頻播放器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android系統(tǒng)自帶樣式 (android:theme)

    Android系統(tǒng)自帶樣式 (android:theme)

    Android系統(tǒng)中自帶樣式分享,需要的朋友可以參考下
    2013-01-01
  • Android ListView控件使用方法

    Android ListView控件使用方法

    這篇文章主要為大家詳細(xì)介紹了Android ListView控件的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android實戰(zhàn)之Cocos游戲容器搭建

    Android實戰(zhàn)之Cocos游戲容器搭建

    這篇文章主要介紹了Android實戰(zhàn)之Cocos游戲容器搭建,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-06-06

最新評論