Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中適用於ListView、GridView等組件的通用Adapter

Android中適用於ListView、GridView等組件的通用Adapter

編輯:關於Android編程

今天隨便逛逛CSDN,看到主頁上推薦了一篇文章Android 快速開發系列 打造萬能的ListView GridView 適配器,剛好這兩天寫項目自己也封裝了類似的CommonAdapter,以前也在github上看到過這樣的庫,於是自己也把自己的代碼再次整理出來與大家分享,也希望能夠在CSDN這個平台上學到更多的東西,下面就一起來看看吧。

平時我們在項目中使用到ListView和GridView組件都是都會用到Adapter,比較多的情況是繼承自BaseAdapter,然後實現getCount、getView等方法,再使用ViewHolder來提高一下效率.我們看下面一個簡單的例子 :

ListView布局文件

fragment_main.xml :



    


ListView子項的布局文件

listview_item_layout.xml :




    

    


曾經我們要寫下的Adapter代碼

public class NormalAdapter extends BaseAdapter {

    Context mContext;

    LayoutInflater mInflater;

    List mDataList;

    /**
     * @param context
     * @param data
     */
    public NormalAdapter(Context context, List data) {
        mContext = context;
        mInflater = LayoutInflater.from(context);
        mDataList = data;
    }

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

    @Override
    public ListViewItem getItem(int position) {
        return mDataList.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview_item_layout, null, false);
            viewHolder = new ViewHolder();
            viewHolder.mImageView = (ImageView) convertView.findViewById(R.id.my_imageview);
            viewHolder.mTextView = (TextView) convertView.findViewById(R.id.my_textview);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.mImageView.setImageResource(getItem(position).mDrawableId);
        viewHolder.mTextView.setText(getItem(position).mText);
        return convertView;
    }

    /**
     * ViewHolder
     * 
     * @author mrsimple
     */
    static class ViewHolder {
        ImageView mImageView;
        TextView mTextView;
    }

}

然而寫過多遍以後我們發現我們總是重復地在寫這些getCount、getItem、getView方法以及ViewHolder,導致了很多重復工作,而且及其無聊,於是我把這些重復工作抽象起來(以前也有在github上看到這樣的通用Adapter實現),整理一下也便於自己使用,也是自己學習的一個過程。下面我們看看使用CommonAdapter後我們做與上面同樣的工作需要怎麼寫。

使用CommonAdapter後要寫的代碼

CommonAdapter listAdapter = new CommonAdapter(getActivity(),
                    R.layout.listview_item_layout, mockListViewItems()) {

                @Override
                protected void fillItemData(CommonViewHolder viewHolder, ListViewItem item) {
                    // 設置圖片
                    viewHolder.setImageForView(R.id.my_imageview, item.mDrawableId);
                    // 設置text
                    viewHolder.setTextForTextView(R.id.my_textview, item.mText);
                }
            }

其中mockListViewImtes是准備了一些數據, 代碼如下 :
        /**
         * 模擬一些數據
         * 
         * @return
         */
        private List mockListViewItems() {
            List dataItems = new ArrayList();
            dataItems.add(new ListViewItem(R.drawable.girl_96, "girl_96.png"));
            dataItems.add(new ListViewItem(R.drawable.fire_96, "fire_96.png"));
            dataItems.add(new ListViewItem(R.drawable.grimace_96, "grimace_96.png"));
            dataItems.add(new ListViewItem(R.drawable.laugh_96, "laugh_96.png"));
            return dataItems;
        }

可以看到,我們的代碼量減少了很多,如果一個項目中有好幾個ListView、GridView等組件,我們就不需要重復做那麼多無聊的工作了。我們看看效果圖 :

\

CommonAdapter實現

/**
 *
 *	created by Mr.Simple, Aug 28, 201412:26:52 PM.
 *	Copyright (c) 2014, [email protected] All Rights Reserved.
 *
 *                #####################################################
 *                #                                                   #
 *                #                       _oo0oo_                     #   
 *                #                      o8888888o                    #
 *                #                      88" . "88                    #
 *                #                      (| -_- |)                    #
 *                #                      0\  =  /0                    #   
 *                #                    ___/`---'\___                  #
 *                #                  .' \\|     |# '.                 #
 *                #                 / \\|||  :  |||# \                #
 *                #                / _||||| -:- |||||- \              #
 *                #               |   | \\\  -  #/ |   |              #
 *                #               | \_|  ''\---/''  |_/ |             #
 *                #               \  .-\__  '-'  ___/-. /             #
 *                #             ___'. .'  /--.--\  `. .'___           #
 *                #          ."" '<  `.___\_<|>_/___.' >' "".         #
 *                #         | | :  `- \`.;`\ _ /`;.`/ - ` : | |       #
 *                #         \  \ `_.   \_ __\ /__ _/   .-` /  /       #
 *                #     =====`-.____`.___ \_____/___.-`___.-'=====    #
 *                #                       `=---='                     #
 *                #     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   #
 *                #                                                   #
 *                #               佛祖保佑         永無BUG              #
 *                #                                                   #
 *                #####################################################
 */

package com.uit.commons;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.List;

/**
 * 這是一個通用、抽象的適配器類,覆寫了BaseAdapter的getCount, getItem, getItemId,
 * getView方法,在getView方法中通過
 * 通用的CommonViewHolder來對convertView的進行處理,並且緩存convertView中的其他View元素
 * ,降低了ListView、GridView 等組件的Adapter和ViewHolder的代碼量.
 * 用戶只需要在fillItemData函數中將第position位置裡的數據填充到listview或者gridview的第position的view中即可
 * ,具體使用實例參考文檔.
 * 
 * @author mrsimple
 * @param  數據源的類型
 */
public abstract class CommonAdapter extends BaseAdapter {

    /**
     * Context
     */
    Context mContext;
    /**
     * 要展示的數據列表
     */
    List mData;
    /**
     * 每一項的布局id,例如R.layout.my_listview_item.
     */
    private int mItemLayoutId = -1;

    /**
     * @param context Context
     * @param itemLayoutResId
     *            每一項(適用於listview、gridview等AbsListView子類)的布局資源id,例如R.layout.
     *            my_listview_item.
     * @param dataSource 數據源
     */
    public CommonAdapter(Context context, int itemLayoutResId, List dataSource) {
        checkParams(context, itemLayoutResId, dataSource);
        mContext = context;
        mItemLayoutId = itemLayoutResId;
        mData = dataSource;
    }

    /**
     * 檢查參數的有效性
     * 
     * @param context
     * @param itemLayoutResId
     * @param dataSource
     */
    private void checkParams(Context context, int itemLayoutResId, List dataSource) {
        if (context == null || itemLayoutResId < 0 || dataSource == null) {
            throw new RuntimeException(
                    "context == null || itemLayoutResId < 0 || dataSource == null, please check your params");
        }
    }

    /**
     * 返回數據的總數
     */
    @Override
    public int getCount() {
        return mData.size();
    }

    /**
     * 返回position位置的數據
     */
    @Override
    public T getItem(int position) {
        return mData.get(position);
    }

    /**
     * item id, 返回position
     */
    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 返回position位置的view, 即listview、gridview的第postion個view
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 獲取ViewHolder
        CommonViewHolder viewHolder = CommonViewHolder.getViewHolder(mContext, convertView,
                mItemLayoutId);
        // 填充數據
        fillItemData(viewHolder, getItem(position));
        // 返回convertview
        return viewHolder.getConvertView();
    }

    /**
     * 用戶必須覆寫該方法來講數據填充到視圖中
     * 
     * @param viewHolder 通用的ViewHolder, 裡面會裝載listview,
     *            gridview等組件的每一項的視圖,並且緩存其子view
     * @param item 數據源的第position項數據
     */
    protected abstract void fillItemData(CommonViewHolder viewHolder, T item);

}

CommonViewHolder實現

/**
 *
 *	created by Mr.Simple, Aug 28, 201412:32:45 PM.
 *	Copyright (c) 2014, [email protected] All Rights Reserved.
 *
 *                #####################################################
 *                #                                                   #
 *                #                       _oo0oo_                     #   
 *                #                      o8888888o                    #
 *                #                      88" . "88                    #
 *                #                      (| -_- |)                    #
 *                #                      0\  =  /0                    #   
 *                #                    ___/`---'\___                  #
 *                #                  .' \\|     |# '.                 #
 *                #                 / \\|||  :  |||# \                #
 *                #                / _||||| -:- |||||- \              #
 *                #               |   | \\\  -  #/ |   |              #
 *                #               | \_|  ''\---/''  |_/ |             #
 *                #               \  .-\__  '-'  ___/-. /             #
 *                #             ___'. .'  /--.--\  `. .'___           #
 *                #          ."" '<  `.___\_<|>_/___.' >' "".         #
 *                #         | | :  `- \`.;`\ _ /`;.`/ - ` : | |       #
 *                #         \  \ `_.   \_ __\ /__ _/   .-` /  /       #
 *                #     =====`-.____`.___ \_____/___.-`___.-'=====    #
 *                #                       `=---='                     #
 *                #     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   #
 *                #                                                   #
 *                #               佛祖保佑         永無BUG              #
 *                #                                                   #
 *                #####################################################
 */

package com.uit.commons;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;

import com.uit.commons.utils.ViewFinder;

/**
 * 這是一個通用的ViewHolder, 將會裝載AbsListView子類的item View, 並且將item
 * view中的子視圖進行緩存和索引,使得用戶能夠方便的獲取這些子view, 減少了代碼重復。
 * 
 * @author mrsimple
 */
public class CommonViewHolder {

    /**
     * 構造函數
     * 
     * @param context Context
     * @param layoutId ListView、GridView或者其他AbsListVew子類的 Item View的資源布局id
     */
    protected CommonViewHolder(Context context, int layoutId) {
        // 初始化布局, 裝載ContentView
        ViewFinder.initContentView(context, layoutId);
        // 將ViewHolder存儲在ContentView的tag中
        ViewFinder.getContentView().setTag(this);
    }

    /**
     * 獲取CommonViewHolder,當convertView為空的時候從布局xml裝載item view,
     * 並且將該CommonViewHolder設置為convertView的tag, 便於復用convertView.
     * 
     * @param context Context
     * @param convertView Item view
     * @param layoutId 布局資源id, 例如R.layout.my_listview_item.
     * @return 通用的CommonViewHolder實例
     */
    public static CommonViewHolder getViewHolder(Context context, View convertView, int layoutId) {
        if (convertView == null) {
            return new CommonViewHolder(context, layoutId);
        }

        return (CommonViewHolder) convertView.getTag();
    }

    /**
     * @return 當前項的convertView, 在構造函數中裝載
     */
    public View getConvertView() {
        return ViewFinder.getContentView();
    }

    /**
     * 為id為textViewId的TextView設置文本內容
     * 
     * @param textViewId 視圖id
     * @param text 要設置的文本內容
     */
    public void setTextForTextView(int textViewId, CharSequence text) {
        TextView textView = ViewFinder.findViewById(textViewId);
        if (textView != null) {
            textView.setText(text);
        }
    }

    /**
     * 為ImageView設置圖片
     * 
     * @param imageViewId ImageView的id, 例如R.id.my_imageview
     * @param drawableId Drawable圖片的id, 例如R.drawable.my_photo
     */
    public void setImageForView(int imageViewId, int drawableId) {
        ImageView imageView = ViewFinder.findViewById(imageViewId);
        if (imageView != null) {
            imageView.setImageResource(drawableId);
        }
    }

    /**
     * 為ImageView設置圖片
     * 
     * @param imageViewId ImageView的id, 例如R.id.my_imageview
     * @param bmp Bitmap圖片
     */
    public void setImageForView(int imageViewId, Bitmap bmp) {
        ImageView imageView = ViewFinder.findViewById(imageViewId);
        if (imageView != null) {
            imageView.setImageBitmap(bmp);
        }
    }

    /**
     * 為CheckBox設置是否選中
     * 
     * @param checkViewId CheckBox的id
     * @param isCheck 是否選中
     */
    public void setCheckForCheckBox(int checkViewId, boolean isCheck) {
        CheckBox checkBox = ViewFinder.findViewById(checkViewId);
        if (checkBox != null) {
            checkBox.setChecked(isCheck);
        }
    }
}


ViewFinder輔助類

/**
 * view finder, 方便查找View。用戶需要在使用時調用initContentView,
 * 將Context和布局id傳進來,然後使用findViewById來獲取需要的view
 * ,findViewById為泛型方法,返回的view則直接是你接收的類型,而不需要進行強制類型轉換.比如,
 * 以前我們在Activity中找一個TextView一般是這樣 : 
 * TextView textView = (TextView)findViewById(viewId); 
 * 如果頁面中的控件比較多,就會有很多的類型轉換,而使用ViewFinder則免去了類型轉換,
 * 示例如下 : 
 * TextView textView = ViewFinder.findViewById(viewId);
 * 
 * @author mrsimple
 */
public final class ViewFinder {

    /**
     * LayoutInflater
     */
    static LayoutInflater mInflater;

    /**
     * 每項的View的sub view Map
     */
    private static SparseArray mViewMap = new SparseArray();

    /**
     * Content View
     */
    static View mContentView;

    /**
     * 初始化ViewFinder, 實際上是獲取到該頁面的ContentView.
     * 
     * @param context
     * @param layoutId
     */
    public static void initContentView(Context context, int layoutId) {
        mInflater = LayoutInflater.from(context);
        mContentView = mInflater.inflate(layoutId, null, false);
        if (mInflater == null || mContentView == null) {
            throw new RuntimeException(
                    "ViewFinder init failed, mInflater == null || mContentView == null.");
        }
    }

    /**
     * @return
     */
    public static View getContentView() {
        return mContentView;
    }

    /**
     * @param viewId
     * @return
     */
    @SuppressWarnings("unchecked")
    public static  T findViewById(int viewId) {
        // 先從view map中查找,如果有的緩存的話直接使用,否則再從mContentView中找
        View tagetView = mViewMap.get(viewId);
        if (tagetView == null) {
            tagetView = mContentView.findViewById(viewId);
            mViewMap.put(viewId, tagetView);
        }
        return tagetView == null ? null : (T) mContentView.findViewById(viewId);
    }
}

代碼都在Github上了,請猛擊這裡。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved