Android ListView中複雜資料流的高效渲染(一)

wutongke發表於2019-02-26

更新:目前已經寫了demo,歡迎討論:Android複雜資料流的“高效”渲染

我們知道Android中的ListView之所以可以實現item的無限載入,是因為對每個item的View 進行了快取複用。ListView的高效效能使得其在App開發中使用非常頻繁,本文主要分析在複雜資料展示時如何更加高效的使用ListView,如微博、facebook、twitter等的feed流需要展示非常多的資料型別:新聞、圖片、網頁連結、視訊,這種情況下ListView進行需要快取各種型別的View,App的記憶體佔用急劇升高……

ListView複用原理

1. 簡單列表複用

首先簡單介紹一下ListView的複用原理,我們知道使用ListView時一般需要結合Adapter使用,繼承BaseAdapter時,一般需要實現四個方法:

    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return null;
    }複製程式碼

其中getView是渲染每個Item時進行回撥生成View的,方法引數convertView就是ListView傳回可以複用的View,當其不為null時,無需重新建立View,可以直接使用convertView,進行資料渲染即可。其原理是當第一次呼叫時ListView直接將生成的View快取到一個ArrayList中,當需要時直接從ArrayList中取出即可:

Android ListView中複雜資料流的高效渲染(一)
Paste_Image.png

2. 複雜列表複用

當列表中有多種型別的view時,我們需要實現BaseAdapter中的:

    @Override
    //返回view型別數量
    public int getViewTypeCount() {
        return super.getViewTypeCount();
    }

    @Override
    //返回每個Item的型別
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }複製程式碼

這種情況下ListView實際為每種型別的Item設定了一個ArrayList進行快取:

Android ListView中複雜資料流的高效渲染(一)
Paste_Image.png

複雜資訊流

此處以微博為例:

  • 轉發帶視訊型別
    Android ListView中複雜資料流的高效渲染(一)
    Paste_Image.png
  • 普通文字+卡片型別

Android ListView中複雜資料流的高效渲染(一)

  • 轉發圖文型別

Android ListView中複雜資料流的高效渲染(一)

此外還有原創圖文型別,原創視訊,原創卡片,系統通知,轉發視訊,轉發圖文,……,微博有多達二十種左右的item型別,每種型別中的View可能包括頭部圖片、文字描述、正文內容、正文圖片、正文視訊、分享操作欄等內容,這些都快取到記憶體中,再加上二十多種型別,想想記憶體的感受……

優化

我們可以看到很多型別中都有相同可以複用的部分,如頭部、分享操作欄等很多item中都是一樣,是否可單獨拿出來呢,我們進行簡單的拆分:

Android ListView中複雜資料流的高效渲染(一)
Paste_Image.png

一個Item我們把它拆為來五個部分,首先頭部、評論操作欄等可以在很多不同型別的資料Item中進行復用,文字、圖片等的View也可以單獨進行復用,而且最重要的是:快取ArrayList中儲存的View數量將會減少,記憶體消耗減了不少

具體實現中的坑

看到這裡,是不是很多同學覺得開啟了新世界的大門,急著進行程式碼的優化?具體的程式碼不方便貼出來,這裡說一下具體實現過程中碰到的坑:

  • item click事件
    由於優化的需求,把邏輯上的一個Item拆分為了多個item,因此每個item上都要設定ItemClick事件。具體實現時可以寫一個基類,在基類中對item click進行處理。
  • cover 按壓效果
    在item 點選時,一般需要有按壓效果,此時邏輯上的item已經進行了拆分,需要策略實現邏輯上item的整體按壓,而不是隻有某個拆分後的item被按壓。
  • divider
    我們知道listview的item之間是有divider的,此時需要設定divider為null,我們通過新增item的方式來實現divider效果。

效果

等填完拆分後的坑,執行程式,觀察前後的效果,記憶體佔用可以減少10~20m,滑動流暢度也提高不少,在低端手機上的效果尤其明顯,掉幀明顯減少。非常建議有需要的同學嘗試。

Other

歡迎關注公眾號wutongke,每天推送移動開發前沿技術文章:

Android ListView中複雜資料流的高效渲染(一)
wutongke

相關文章