打造万能Viewholder,告别重复代码

每次写ListView显示列表都会重复写出if(convertview == null){}else{} 这些重复的代码,既然是重复的,肯定是可以提取复用的。。。

开始咯:

首先CommonAdapter类继承BaseAdapter并实现其方法,因为我们要做到灵活性,所以实体类,item布局都是要传进来的

public CommonAdapter(Context context, List<T> datas, int layoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(context);
        this.mDatas = datas;
        this.layoutId = layoutId;
  }

实现的BaseAdapter的类:

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       return null;
    }



因为我们要使用ViewHolder来进行复用,所以开始编写ViewHolder类:

传统模式需要使用convertView.setTag(holder)将holder和adapter结合起来,所以我们现在需要将各种控件存储起来,然后再需要使用的地方取出这个控件进行使用就好了,在这里推荐使用SparseArray,实际上它内部也是维护的一个map集合,但是它比HaseMap效率要更高,可以看下官方解释

SparseArrays map integers to Objects.  Unlike a normal array of Objects,there can be gaps in the indices.  It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry object for each mapping.


private SparseArray<View> mViews;

我们可以开始编写一个ViewHolder的入口来供Adapter中的getView()方法调用

public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
        if (convertView == null) {
            return new ViewHolder(context, parent, layoutId, position);
        } else {
            ViewHolder holder = (ViewHolder) convertView.getTag();
            holder.mPosition = position;
            return holder;
        }
    }

还是和传统模式的复用convertView一样的,当convertView不为空的时候,还是使用getTag(),当为空的时候通过使用new ViewHolder来进行初始化操作

public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        this.mPosition = position;
        this.mViews = new SparseArray<View>();
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        mConvertView.setTag(this);
    }

ViewHolder里面传入我们需要的参数,当然包括item布局文件


有了这样一个ViewHolder类之后,并且提供了调用入口,这时候我们就可以在BaseAdapter中的getView()中进行调用了

@Override
   public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent, layoutId, position);
        convert(viewHolder, getItem(position));
        return viewHolder.getConvertView();
   }


这里返回的是Viewholder中的getConvertView()

public View getConvertView() {
        return mConvertView;
    }


getView中我们对外提供了一个抽象方法convert()来供调用,返回了holder和我们的实体

public abstract void convert(ViewHolder holder, T t);


好了,CommonAdapter中基本就需要这些东西了


现在回到我们的ViewHolder类中,要使用ViewHolder,所以我们要怎么获取到控件呢

上面有讲到过,使用SparseArray来存储View控件

public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
   }

和HashMap一样,通过key来获取value,如果没有就使用convertView来findViewById()来获取控件,再添加到集合里并返回


到此我们的ViewHolder就已经编写差不多了


那如何使用呢?

 CommonAdapter<MenuEntity> adapter = new CommonAdapter<MenuEntity>(context,menus,R.layout.item_list) {
            @Override
            public void convert(ViewHolder holder, MenuEntity menuEntity) {
                TextView tv = holder.getView(R.id.tv);
                tv_kind_name.setText(menuEntity.name);
            }
    };

可以直接在MainActivity中使用内部类来实现重写convert(),当然也可以重新新建一个类来继承我们的CommonAdapter,然后实现里面的方法咯


为了更简洁,我们还可以做如下优化:


/**
     * 设置TextView的值
     *
     * @param viewId
     * @param value
     * @return
     */
    public ViewHolder setText(int viewId, String value) {
        TextView textView = getView(viewId);
        textView.setText(value);
        return this;
    }


    public ViewHolder setImageResource(int viewId, int resId) {
        ImageView view = getView(viewId);
        view.setImageResource(resId);
        return this;
    }


    public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
        ImageView view = getView(viewId);
        view.setImageBitmap(bitmap);
        return this;
    }

我们可以直接在ViewHolder类中添加如是方法,获取控件并设置值,这个时候我们的convert中就可以变成这样:

 CommonAdapter<MenuEntity> adapter = new CommonAdapter<MenuEntity>(context,menus,R.layout.item_gamelist_kind_list) {
            @Override
            public void convert(ViewHolder holder, MenuEntity menuEntity) {
              holder.setText(R.id.tv_kind_name,menuEntity.menuName);
            }
        };

并且还可以连" . " 哦~


好了 至此我们的类已经全部编写完成,以后我们每次要使用BaseAdapter的时候就只需要new CommonAdapter就好了,是不是很简洁 @@ 


附上Utils源码连接:http://download.csdn.net/detail/flyingzhlunasea/9516487


欢迎指正!!!










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值