1. 程式人生 > >安卓效能優化之懶載入(View的懶載入)

安卓效能優化之懶載入(View的懶載入)

1、背景:為什麼需要View的懶載入。      

    我們在做安卓專案的時候,經常會有一個使用場景:需要在執行時根據資料動態決定顯示或隱藏某個View和佈局。  

    上述場景,我們通常的解決方案就是:就是把可能用到的View先寫在佈局裡,再初始化其可見性都設為View.GONE,然後在程式碼中根據資料動態的更改它的可見性。  

    雖然這樣的實現,邏輯簡單而且控制起來比較靈活;但是也存在一定的缺點耗費資源。

    因為即使把View的初始可見View.GONE但是在Inflate佈局的時候View仍然會被Inflate,故而:

    (1)仍然會建立物件;

    (2)仍然會被例項化;

    (3)仍然會被設定屬性從而導致耗費記憶體等資源。        

    這時候,我們就需要View的懶載入。        

2、什麼是ViewStub。  

    (1)ViewStub一個是直接繼承於View的類。

    (2)實質上是一個寬高都為 0 的不可見 View。        

3、為什麼能用ViewStub實現View的懶載入

    ViewStub的特性: 

    (1)在初始化佈局檔案時,程式無需初始化<ViewStub>標籤所指向的佈局檔案。 只有在特定的條件下,所指向的佈局檔案才需要被渲染,且此佈局檔案直接將當前的 <ViewStub> 替換掉。但這裡的替換並不是完全意義上的替換,佈局檔案的 layout params 是以 ViewStub 為優先。

    (2)當初次渲染布局檔案時,ViewStub 控制元件雖然也佔據記憶體, 但是相比於其他控制元件, 它所佔記憶體很小. 它主要是作為一個“佔位符”, 放置於 View Tree中, 且它本身是不可見的。  

    由於具有以上特性,只有當一個ViewStub的inflate()方法被呼叫或者被設為View.VISIBILITY時,此時ViewStub會把設定的佈局才會被建立對應的物件和例項化,並替換當前ViewStub的位置,顯示相應的效果。雖然一開始ViewStub就存在於檢視樹中,但是直到setVisibility(int)或inflate()方法被呼叫時才消耗資源,否則是不載入控制元件的,因此消耗的資源小。故而, ViewStub可以實現View的懶載入。  

4、實現方法  

(1)關鍵點      

    <ViewStub>標籤可以看成是一個“佔位符“,可以看成自身是不呈現任何UI效果的檢視容器,主要就是用於存放真實的佈局和檢視,所以除了設定必要的尺寸屬性和位置之外,通常必須設定三個重要屬性和一個回撥監聽介面:

        <1>android:id

                ——ViewStub 自身的Id,無論是否被inflate,都可以通過findViewById拿到對應的ViewStub控制元件本身。  

        <2>android:inflatedId

                ——ViewStub設定的被對映的佈局檔案中的跟節點的Id,inflate之後可以通過findViewById獲取到對應的被對映的佈局物件。  

        <3>android:layout

                ——將要對映的佈局檔名

        <4>ViewStub.OnInflateListener

                ——當ViewStub成功對映預先設定的佈局會觸發回撥  

(2)使用方法      

    設定完上述關鍵點,在程式中呼叫 inflate() 方法就能載入對應的layout。  

    還可以設定 Visibility 為 VISIBLE 或 INVISIBLE,也會觸發 inflate()。 但是這裡只會在首次使用 setVisibility() 會載入要渲染的佈局檔案。再次使用只是單純的設定可見性。  

    對 inflate() 操作也只能進行一次,因為 inflate() 的時候是其指向的佈局檔案替換掉當前 <ViewStub> 標籤。之後, 原來的佈局檔案中就沒有 <ViewStub> 標籤了。因此,如果多次 inflate() 操作,會報錯:ViewStub must have a non-null ViewGroup viewParent。  

(3)demo  

        <1>建立將要被對映的佈局

建立將要被對映的佈局​​​​​

        <2>建立主佈局引入ViewStub

建立主佈局引入ViewStub

        <3>實現MainActivity

實現MainActivity