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

上篇Android ListView中復(fù)雜數(shù)據(jù)流的高效渲染文章中介紹如何高效利用ListView的緩存進(jìn)行渲染。之后有挺多同學(xué)有些疑惑貌亭,希望可以有一個(gè)demo花墩,于是利用業(yè)余時(shí)間把demo櫓出來(lái)了动壤,如果有什么問(wèn)題大家可以評(píng)論或者在ComplexDataStream issue中提issue反璃。這里貼一下demo的地址:ComplexDataStream丧失。另個(gè)人覺(jué)得這個(gè)思路實(shí)際增加了代碼復(fù)雜度恕汇,在邏輯上并不高效阀坏,于是在題目中加了引號(hào)波势,但是實(shí)測(cè)一個(gè)復(fù)雜列表中可以節(jié)約10-20m的內(nèi)存翎朱,這一點(diǎn)是很有誘惑力的。下面結(jié)合代碼介紹一下尺铣。

代碼結(jié)構(gòu)

Paste_Image.png
  • Model
    model中是所有的原始數(shù)據(jù)類拴曲,這里為了方便,每種數(shù)據(jù)的名字實(shí)際包含了需要展示的模型:如CardWithTitleItem數(shù)據(jù)實(shí)際需要展示一個(gè)標(biāo)題和一個(gè)卡片凛忿,HeaderImageCardItem需要展示一個(gè)頭部澈灼、圖片、卡片店溢。
Paste_Image.png
Paste_Image.png
  • Adapter
    Adapter中放置了adapter和各種類型的holder叁熔,這里把多種數(shù)據(jù)類型拆分成了card、divider床牧、header荣回、image、link戈咳、text心软、title壕吹,并為每種類型設(shè)置了相應(yīng)的布局。

  • Util
    Util中設(shè)置如何transform數(shù)據(jù)到相應(yīng)的展示模版删铃,以及解決按壓效果的問(wèn)題耳贬。

代碼思路

我們的目的是將復(fù)雜的數(shù)據(jù)類型進(jìn)行拆分,從而達(dá)到細(xì)顆粒的view復(fù)用猎唁,降低內(nèi)存占用效拭。

  1. 確定拆分后的展示類型,這里使用了一個(gè)enum類型:
public enum ItemType {
    TITLE,
    CARD,
    HEADER,
    IMAGE,
    TEXT,
    LINK,
    DIVIDER
}
  1. transform數(shù)據(jù)到模板胖秒,拆分后一個(gè)數(shù)據(jù)類型對(duì)應(yīng)多個(gè)模板缎患,這里我們使用hashmap建立數(shù)據(jù)到模板的影射關(guān)系:
private static Map<Class, List<ItemType>> map = new HashMap<>();
    public static List<ItemWrap> getTransformedItem(List<BaseItem> baseItems) {
        List<ItemWrap> itemWraps = new ArrayList<>();
        for (BaseItem baseItem : baseItems) {
            for (ItemType itemType : map.get(baseItem.getClass())) {
                ItemWrap temp = new ItemWrap(baseItem, itemType);
                itemWraps.add(temp);
                baseItem.itemWraps.add(temp);
            }
            ItemWrap divider = new ItemWrap(baseItem, ItemType.DIVIDER);
            itemWraps.add(divider);
            baseItem.itemWraps.add(divider);
        }
        return itemWraps;
    }

getTransformedItem方法將原始數(shù)據(jù)進(jìn)行拆分,注意每種原始數(shù)據(jù)類型中都要加入divider模板阎肝,用于展示ListView的分割線挤渔。

  1. 根據(jù)不同的展示類型提供不同的view:
public static View createItemView(ItemType itemType) {
        View view = null;
        BaseHolder baseHolder = null;
        switch (itemType) {
            case TITLE:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.title_item, null);
                baseHolder = new TitleHolder();
                break;
            case CARD:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.card_item, null);
                baseHolder = new CardHolder();
                break;
            case TEXT:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.text_item, null);
                baseHolder = new TextHolder();
                break;
            case IMAGE:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.image_item, null);
                baseHolder = new ImageHolder();
                break;
            case LINK:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.link_item, null);
                baseHolder = new LinkHolder();
                break;
            case HEADER:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.header_item, null);
                baseHolder = new HeaderHolder();
                break;
            case DIVIDER:
                view = LayoutInflater.from(_Application.applicationContext).inflate(R.layout.divider_item, null);
                baseHolder = new DividerHolder();
                break;
        }
        baseHolder.setup(view);
        view.setTag(baseHolder);
        return view;
    }
  1. 按壓效果的實(shí)現(xiàn)
    對(duì)數(shù)據(jù)進(jìn)行拆分后,有一個(gè)坑就是按壓效果的實(shí)現(xiàn)风题,這個(gè)時(shí)候listView中的每個(gè)item都不是一個(gè)完整的原始數(shù)據(jù)判导,要實(shí)現(xiàn)一個(gè)整體的按壓效果,demo的思路是:


    Paste_Image.png

    當(dāng)按壓任意一個(gè)view時(shí)沛硅,通知相應(yīng)的item眼刃,改變item包含的所有view的狀態(tài)。具體實(shí)現(xiàn)時(shí)定義了一個(gè)BackgroundLinearLayout:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            if (mListener != null) {
                mListener.onStatePress(false);
            }
        } else if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (mListener != null) {
                mListener.onStatePress(true);
            }
        } else if (ev.getAction() == MotionEvent.ACTION_CANCEL) {
            if (mListener != null) {
                mListener.onStatePress(false);
            }
        }
        super.dispatchTouchEvent(ev);
        return true;
    }

可以完成view按壓的回調(diào)摇肌。
但是每個(gè)holder需要如思路圖所示綁定到View擂红,綁定可以在adapter的getview中完成。:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ItemWrap itemWrap = (ItemWrap) getItem(position);
        if(convertView == null){
            convertView = ItemWrapHelper.getItemView(itemWrap.getItemType());
        }else {
            ((ItemWrap)(convertView.getTag(R.string.tag_key))).unBindView();
        }
        convertView.setTag(R.string.tag_key, itemWrap);
        BaseHolder baseHolder = (BaseHolder) convertView.getTag();
        baseHolder.render(itemWrap.getBaseItem());
        itemWrap.bindView(convertView);
        return convertView;
    }

基本demo就完成了围小,按壓效果如圖:


Paste_Image.png

總結(jié)

由于主要展現(xiàn)功能昵骤,界面沒(méi)有進(jìn)行太多調(diào)整,另外mock數(shù)據(jù)是復(fù)制了部分[one 一個(gè)]應(yīng)用的數(shù)據(jù)肯适,表示感謝变秦。代碼中有什么問(wèn)題,或者有什么不合理的地方框舔,感興趣的同學(xué)可以建立pull request蹦玫,歡迎討論。項(xiàng)目地址ComplexDataStream刘绣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末樱溉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子额港,更是在濱河造成了極大的恐慌饺窿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件移斩,死亡現(xiàn)場(chǎng)離奇詭異肚医,居然都是意外死亡绢馍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門肠套,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)舰涌,“玉大人,你說(shuō)我怎么就攤上這事你稚〈砂遥” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵刁赖,是天一觀的道長(zhǎng)搁痛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宇弛,這世上最難降的妖魔是什么鸡典? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮枪芒,結(jié)果婚禮上彻况,老公的妹妹穿的比我還像新娘。我一直安慰自己舅踪,他們只是感情好纽甘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著抽碌,像睡著了一般悍赢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咬展,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天泽裳,我揣著相機(jī)與錄音瞒斩,去河邊找鬼破婆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胸囱,可吹牛的內(nèi)容都是我干的祷舀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼烹笔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼裳扯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起谤职,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饰豺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后允蜈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體冤吨,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒿柳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漩蟆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垒探。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怠李,靈堂內(nèi)的尸體忽然破棺而出圾叼,到底是詐尸還是另有隱情,我是刑警寧澤捺癞,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布夷蚊,位于F島的核電站,受9級(jí)特大地震影響髓介,放射性物質(zhì)發(fā)生泄漏撬码。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一版保、第九天 我趴在偏房一處隱蔽的房頂上張望呜笑。 院中可真熱鬧,春花似錦彻犁、人聲如沸叫胁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驼鹅。三九已至,卻和暖如春森篷,著一層夾襖步出監(jiān)牢的瞬間输钩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工仲智, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留买乃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓钓辆,卻偏偏與公主長(zhǎng)得像剪验,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子前联,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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