Android ListView中復(fù)雜數(shù)據(jù)流的高效渲染

更新:目前已經(jīng)寫了demo,歡迎討論:Android復(fù)雜數(shù)據(jù)流的“高效”渲染

我們知道Android中的ListView之所以可以實(shí)現(xiàn)item的無限加載,是因?yàn)閷γ總€(gè)item的View 進(jìn)行了緩存復(fù)用。ListView的高效性能使得其在App開發(fā)中使用非常頻繁,本文主要分析在復(fù)雜數(shù)據(jù)展示時(shí)如何更加高效的使用ListView,如微博、facebook、twitter等的feed流需要展示非常多的數(shù)據(jù)類型:新聞、圖片、網(wǎng)頁鏈接、視頻,這種情況下ListView進(jìn)行需要緩存各種類型的View,App的內(nèi)存占用急劇升高……

ListView復(fù)用原理

1. 簡單列表復(fù)用

首先簡單介紹一下ListView的復(fù)用原理,我們知道使用ListView時(shí)一般需要結(jié)合Adapter使用,繼承BaseAdapter時(shí),一般需要實(shí)現(xiàn)四個(gè)方法:

    @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;
    }

其中g(shù)etView是渲染每個(gè)Item時(shí)進(jìn)行回調(diào)生成View的,方法參數(shù)convertView就是ListView傳回可以復(fù)用的View,當(dāng)其不為null時(shí),無需重新創(chuàng)建View,可以直接使用convertView,進(jìn)行數(shù)據(jù)渲染即可。其原理是當(dāng)?shù)谝淮握{(diào)用時(shí)ListView直接將生成的View緩存到一個(gè)ArrayList<View>中,當(dāng)需要時(shí)直接從ArrayList中取出即可:

Paste_Image.png

2. 復(fù)雜列表復(fù)用

當(dāng)列表中有多種類型的view時(shí),我們需要實(shí)現(xiàn)BaseAdapter中的:

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

    @Override
    //返回每個(gè)Item的類型
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

這種情況下ListView實(shí)際為每種類型的Item設(shè)置了一個(gè)ArrayList進(jìn)行緩存:

Paste_Image.png

復(fù)雜信息流

此處以微博為例:

  • 轉(zhuǎn)發(fā)帶視頻類型


    Paste_Image.png
  • 普通文字+卡片類型
  • 轉(zhuǎn)發(fā)圖文類型

此外還有原創(chuàng)圖文類型,原創(chuàng)視頻,原創(chuàng)卡片,系統(tǒng)通知,轉(zhuǎn)發(fā)視頻,轉(zhuǎn)發(fā)圖文,……,微博有多達(dá)二十種左右的item類型,每種類型中的View可能包括頭部圖片、文字描述、正文內(nèi)容、正文圖片、正文視頻、分享操作欄等內(nèi)容,這些都緩存到內(nèi)存中,再加上二十多種類型,想想內(nèi)存的感受……

優(yōu)化

我們可以看到很多類型中都有相同可以復(fù)用的部分,如頭部、分享操作欄等很多item中都是一樣,是否可單獨(dú)拿出來呢,我們進(jìn)行簡單的拆分:

Paste_Image.png

一個(gè)Item我們把它拆為來五個(gè)部分,首先頭部、評論操作欄等可以在很多不同類型的數(shù)據(jù)Item中進(jìn)行復(fù)用,文字、圖片等的View也可以單獨(dú)進(jìn)行復(fù)用,而且最重要的是:緩存ArrayList中保存的View數(shù)量將會減少,內(nèi)存消耗減了不少

具體實(shí)現(xiàn)中的坑

看到這里,是不是很多同學(xué)覺得打開了新世界的大門,急著進(jìn)行代碼的優(yōu)化?具體的代碼不方便貼出來,這里說一下具體實(shí)現(xiàn)過程中碰到的坑:

  • item click事件
    由于優(yōu)化的需求,把邏輯上的一個(gè)Item拆分為了多個(gè)item,因此每個(gè)item上都要設(shè)置ItemClick事件。具體實(shí)現(xiàn)時(shí)可以寫一個(gè)基類,在基類中對item click進(jìn)行處理。
  • cover 按壓效果
    在item 點(diǎn)擊時(shí),一般需要有按壓效果,此時(shí)邏輯上的item已經(jīng)進(jìn)行了拆分,需要策略實(shí)現(xiàn)邏輯上item的整體按壓,而不是只有某個(gè)拆分后的item被按壓。
  • divider
    我們知道listview的item之間是有divider的,此時(shí)需要設(shè)置divider為null,我們通過添加item的方式來實(shí)現(xiàn)divider效果。

效果

等填完拆分后的坑,運(yùn)行程序,觀察前后的效果,內(nèi)存占用可以減少10~20m,滑動流暢度也提高不少,在低端手機(jī)上的效果尤其明顯,掉幀明顯減少。非常建議有需要的同學(xué)嘗試。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容