zoukankan      html  css  js  c++  java
  • Android中适用于ListView、GridView等组件的通用Adapter

        今天随便逛逛CSDN,看到主页上推荐了一篇文章Android 高速开发系列 打造万能的ListView GridView 适配器,刚好这两天写项目自己也封装了相似的CommonAdapter,曾经也在github上看到过这种库,于是自己也把自己的代码再次整理出来与大家分享,也希望可以在CSDN这个平台上学到很多其它的东西,以下就一起来看看吧。

        平时我们在项目中使用到ListView和GridView组件都是都会用到Adapter,比較多的情况是继承自BaseAdapter,然后实现getCount、getView等方法,再使用ViewHolder来提高一下效率.我们看以下一个简单的样例 :

    ListView布局文件

    fragment_main.xml :

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.example.push_demo_1.MainActivity$PlaceholderFragment" >
    
        <ListView
            android:id="@+id/my_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </RelativeLayout>
    

    ListView子项的布局文件

    listview_item_layout.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
    
        <ImageView
            android:id="@+id/my_imageview"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:contentDescription="@string/app_name" />
    
        <TextView
            android:id="@+id/my_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:textSize="18sp" />
    
    </LinearLayout>

    曾经我们要写下的Adapter代码

    public class NormalAdapter extends BaseAdapter {
    
        Context mContext;
    
        LayoutInflater mInflater;
    
        List<ListViewItem> mDataList;
    
        /**
         * @param context
         * @param data
         */
        public NormalAdapter(Context context, List<ListViewItem> 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<ListViewItem> listAdapter = new CommonAdapter<ListViewItem>(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<ListViewItem> mockListViewItems() {
                List<ListViewItem> dataItems = new ArrayList<ListViewItem>();
                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, hehonghui@umeng.com 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 <T> 数据源的类型
     */
    public abstract class CommonAdapter<T> extends BaseAdapter {
    
        /**
         * Context
         */
        Context mContext;
        /**
         * 要展示的数据列表
         */
        List<T> 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<T> 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<T> 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, hehonghui@umeng.com 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<View> mViewMap = new SparseArray<View>();
    
        /**
         * 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 extends View> 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上了,请猛击这里

  • 相关阅读:
    Android之输入框光标和Hint的位置
    Android之TextView密码输入变星号时间
    Android之布局onClick属性写法规则
    Android对话框之dismiss和cancel和hide区别
    Android Studio开发第四篇版本管理Git(下)
    Android对话框之Context
    [知识库:python-tornado]异步调用中的上下文控制Tornado stack context
    在 CentOS 下手工安装 Docker v1.1x
    Docker: 如何修改 Docker 的镜像存储位置
    Docker学习记录3: 搭建 Private Registry
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4236914.html
Copyright © 2011-2022 走看看