ListView的Adapter及ViewHolder封裝

第一次寫(xiě)博客定躏,同時(shí)也是Android初學(xué)者澜掩,想在博客中記錄自己所學(xué)的一點(diǎn)知識(shí)购披,也算是總結(jié)吧。如果有什么不對(duì)的地方還請(qǐng)指證肩榕,好了下面直接進(jìn)入主題刚陡。

未封裝前

首先我們來(lái)看下沒(méi)有封裝前的,相信大家都很熟悉了株汉,但為了后面的封裝我寫(xiě)了一個(gè)簡(jiǎn)單的Adapter筐乳。代碼中的UIUtils為我寫(xiě)的工具類(lèi),就是對(duì)View.inflate的封裝乔妈,大家當(dāng)做View.inflate就好蝙云。(- -!)

private String[] data = new String[] { "hello", "world" };

public class Adapter extends BaseAdapter {

    @Override
    public int getCount() {
        return data.length;
    }
    @Override
    public String getItem(int position) {
        return data[position];
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            //1, 加載布局文件
            convertView = UIUtils.inflate(R.layout.list_item);
            holder = new ViewHolder();
            //2, 初始化控件 findViewById
            holder.tv = (TextView) convertView.findViewById(R.id.tv);
            //3, 打tag
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        //4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
        String content = getItem(position);
        holder.tv.setText(content);
        return convertView;
    }
    static class ViewHolder {
        TextView tv;
    }
}

看完之后大家可能覺(jué)得沒(méi)什么,寫(xiě)起來(lái)也很簡(jiǎn)單路召,那為什么要封裝呢勃刨?是的,如果你的項(xiàng)目中是使用一個(gè)listview那么寫(xiě)起來(lái)是不用封裝股淡,但如果你的項(xiàng)目中使用大量的ListView身隐,那你就要為每個(gè)ListView寫(xiě)個(gè)Adapter。從上述的代碼中我們可以看出有很多事重復(fù)的工作唯灵。那么這時(shí)候我們進(jìn)行封裝可以使我們的代碼量減少很多贾铝。

第一步封裝

首先我們觀察adapter中有三個(gè)方法是固定寫(xiě)法

  • getCount()
  • getItem(int position)
  • getItemId(int position)

上述的三個(gè)方法基本都是固定寫(xiě)法沒(méi)上面變動(dòng),唯一變動(dòng)的就是數(shù)據(jù)的類(lèi)型,那么我們可以寫(xiě)一個(gè)ArrayList<T>并傳入一個(gè)泛型垢揩,這樣數(shù)據(jù)類(lèi)型的問(wèn)題就解決了大脉。然后就可以進(jìn)行封裝。在構(gòu)造方法中得到這個(gè)data然后根據(jù)data來(lái)適配水孩。

public abstract class MyBaseAdapter<T> extends BaseAdapter {

    private ArrayList<T> data;

    public MyBaseAdapter(ArrayList<T> data) {
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public T getItem(int position) {
        return data.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
           ... //代碼和上面的getView一樣
    }
    ... //ViewHolder
}

這樣就封裝了三個(gè)方法,如下寫(xiě)個(gè)adapter繼承琐驴,這樣就只需簡(jiǎn)傳入一個(gè)自定義data就行了(當(dāng)然這里我只是簡(jiǎn)單的寫(xiě)個(gè)String俘种,你可以根據(jù)需求傳入你需要類(lèi)型的泛型)

class MyAdapter extends MyBaseAdapter<String> {

    public MyAdapter(ArrayList<String> data) {
        super(data);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            //1, 加載布局文件
            convertView = UIUtils.inflate(R.layout.list_item_home);
            holder = new ViewHolder();

            //2, 初始化控件 findViewById
            holder.tv = (TextView) convertView.findViewById(R.id.tv);

            //3, 打tag
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        //4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
        String content = getItem(position);
        holder.tv.setText(content);

        return convertView;
    }
}

ok,到了這里第一步封裝就完成了绝淡,以后的代碼中就省了不少重復(fù)的代碼宙刘。

第二步封裝

到了第二步,也是最難啃的骨頭牢酵,那就是對(duì)getView(...)進(jìn)行封裝悬包。相信大家也發(fā)現(xiàn)了getView(...)很臃腫,但它們填充的布局馍乙,還有ViewHolder又都不一樣布近,那怎么進(jìn)行封裝呢?相信仔細(xì)的童鞋發(fā)現(xiàn)了我在getView(...)中寫(xiě)了四個(gè)步驟

  1. 加載布局文件
  2. 初始化控件 findViewById
  3. 打tag
  4. 根據(jù)數(shù)據(jù)來(lái)刷新界面

接下來(lái)就圍繞這四部進(jìn)行封裝就可以了丝格。

新建一個(gè)BaseHolder類(lèi)

在BaseHolder中對(duì)這四個(gè)步驟進(jìn)行封裝

public abstract class BaseHolder<T> {

    private View mRootView; //一個(gè)item布局
    private T data;

    public BaseHolder() {
        mRootView = initView();

        //3, 打tag
        mRootView.setTag(this);
    }


    //1, 加載布局文件
    //2, 初始化控件
    public abstract View initView();  //具體布局交由子類(lèi)實(shí)現(xiàn)

    //4, 根據(jù)數(shù)據(jù)刷新界面
    public abstract void refreshData(T data);  //具體數(shù)據(jù)由子類(lèi)提供

    //item的布局對(duì)象
    public View getView() {
        return mRootView;
    }

    //設(shè)置item的數(shù)據(jù)
    public void setData(T data) {
        this.data = data;
        refreshData(data);
    }

    //獲取item的數(shù)據(jù)
    public T getData() {
        return data;
    }
}

這是運(yùn)用在我們的MyAdapter上撑瞧,在用的時(shí)候我們會(huì)發(fā)現(xiàn)BaseHolder是不能new的,這時(shí)候我們就需要在MyBaseAdapter中定義一個(gè)抽象方法getHolder()显蝌,交由子類(lèi)來(lái)實(shí)現(xiàn)

public View getView(int position, View convertView, ViewGroup parent) {
    BaseHolder holder = getHolder();
    if (convertView == null) {
        //1, 加載布局文件
        //2, 初始化控件 findViewById
        //3, 打tag
        holder = getHolder();
           
    } else {
       holder = (ViewHolder) convertView.getTag();
    }
    //4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
    holder.setData(getItem(position));

    //return convertView; //這里不能直接返回convertView预伺,會(huì)出現(xiàn)空指針異常
    return holder.getView();
}
public abstract BaseHolder getHolder();  //交由子類(lèi)來(lái)實(shí)現(xiàn)

進(jìn)行到了這一步相信大家也能發(fā)現(xiàn),我們必須在新建一個(gè)Holder繼承BaseHolder曼尊,確實(shí)如此(- -!)酬诀。

public class Holder extends BaseHolder<String> {

    private TextView tvContent;

    @Override
    public View initView() {
        // 1. 加載布局
        //這時(shí)候你需要的填充你所需要的布局了
        View view = UIUtils.inflate(R.layout.list_item_home); 
        // 2. 初始化控件
        tvContent = (TextView) view.findViewById(R.id.tv_content);
        return view;
    }

    @Override
    public void refreshView(String data) { //string為前面的定義的泛型
        tvContent.setText(data);
    }
}

到了這一步就完全封裝好了÷嫫玻看下效果吧瞒御。

class Adapter extends MyBaseAdapter<String> {

    public HomeAdapter(ArrayList<String> data) {
        super(data);
    }

    @Override
    public BaseHolder<String> getHolder() {
        return new Holder();
    }
}

這樣以后再寫(xiě)adapter簡(jiǎn)單的幾行就搞定了。

小結(jié)

在來(lái)簡(jiǎn)單的說(shuō)下流程吧艾船,要完成封裝我們需要些兩個(gè)基類(lèi)MyBaseAdapter和BaseHolder在兩個(gè)類(lèi)定義抽象方法葵腹,由子類(lèi)實(shí)現(xiàn)具體的操作便能完成對(duì)BaseAdapter的封裝。使用時(shí)也需要要定義2個(gè)類(lèi)繼承它們屿岂,即定義你自己的Holder和Adapter践宴,在其中實(shí)現(xiàn)邏輯,這樣可已減少在activity中使用adapter時(shí)的代碼量爷怀∽杓纾可能理解起來(lái)有點(diǎn)費(fèi)解,而且也可能會(huì)有人說(shuō)還不如不封裝,封裝了反而顯得的麻煩烤惊,但我相信在大型項(xiàng)目用起來(lái)效果應(yīng)該會(huì)比不封裝好一些乔煞。

ps:第一次寫(xiě)博客,可能有些地方考慮的不是很周到柒室,請(qǐng)大家見(jiàn)諒渡贾。就算沒(méi)人看,未來(lái)會(huì)堅(jiān)持下去雄右。當(dāng)做是自己的筆記和總結(jié)吧空骚!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市擂仍,隨后出現(xiàn)的幾起案子囤屹,更是在濱河造成了極大的恐慌,老刑警劉巖逢渔,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肋坚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡肃廓,警方通過(guò)查閱死者的電腦和手機(jī)智厌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)亿昏,“玉大人峦剔,你說(shuō)我怎么就攤上這事〗枪常” “怎么了吝沫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)递礼。 經(jīng)常有香客問(wèn)我惨险,道長(zhǎng),這世上最難降的妖魔是什么脊髓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任辫愉,我火速辦了婚禮,結(jié)果婚禮上将硝,老公的妹妹穿的比我還像新娘恭朗。我一直安慰自己,他們只是感情好依疼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布痰腮。 她就那樣靜靜地躺著,像睡著了一般律罢。 火紅的嫁衣襯著肌膚如雪膀值。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音沧踏,去河邊找鬼歌逢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翘狱,可吹牛的內(nèi)容都是我干的秘案。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼潦匈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼踏烙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起历等,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辟癌,沒(méi)想到半個(gè)月后寒屯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黍少,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寡夹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厂置。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡菩掏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昵济,到底是詐尸還是另有隱情智绸,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布访忿,位于F島的核電站瞧栗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏海铆。R本人自食惡果不足惜迹恐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卧斟。 院中可真熱鬧殴边,春花似錦、人聲如沸珍语。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)廊酣。三九已至能耻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晓猛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工饿幅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戒职。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓栗恩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親洪燥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子磕秤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,151評(píng)論 25 707
  • Android源碼之ListView的適配器模式 Adapter Pattern適配器模式分為兩種,即類(lèi)適配器芒篷,對(duì)...
    cxm11閱讀 4,217評(píng)論 1 30
  • 一搜变、適用場(chǎng)景 ListViewListview是一個(gè)很重要的組件,它以列表的形式根據(jù)數(shù)據(jù)的長(zhǎng)自適應(yīng)展示具體內(nèi)容,用...
    Geeks_Liu閱讀 10,671評(píng)論 1 28
  • 今天睡前十分鐘腹部運(yùn)動(dòng) 又看完了轉(zhuǎn)角遇到愛(ài) 又自己看了命中注定我愛(ài)你 唱了轉(zhuǎn)角愛(ài)针炉, 寫(xiě)了每日書(shū)值日分享 貽貝買(mǎi)了幾...
    水仙與惡魔Slog閱讀 301評(píng)論 0 0
  • 最近項(xiàng)目需要對(duì)一些條目進(jìn)行排序挠他,這些條目都是漢字詞組,使用Python傳統(tǒng)的.sort,或sorted都失敗了篡帕,原...
    vola_lei閱讀 6,384評(píng)論 0 5