android打造万能适配器
1、概述
相信做Android开发的写得最多的就是ListView,GridView的适配器吧,记得以前开发一同事开发项目,一个项目下来基本就一直在写ListView的Adapter都快吐了~~~对于Adapter一般都继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式,其实大部分的代码基本都是类似的。
本篇博客为快速开发系列的第一篇,将一步一步带您封装出一个通用的Adapter
2、创建ViewHolder
首先分析下ViewHolder的作用,通过convertView.setTag与convertView进行绑定,然后当convertView复用时,直接从与之对于的ViewHolder(getTag)中拿到convertView布局中的控件,省去了findViewById的时间~
也就是说,实际上们每个convertView会绑定一个ViewHolder对象,这个viewHolder主要用于帮convertView存储布局中的控件。
那么我们只要写出一个通用的ViewHolder,然后对于任意的convertView,提供一个对象让其setTag即可;
既然是通用,那么我们这个ViewHolder就不可能含有各种控件的成员变量了,因为每个Item的布局是不同的,最好的方式是什么呢?
提供一个容器,专门存每个Item布局中的所有控件,而且还要能够查找出来;既然需要查找,那么ListView肯定是不行了,需要一个键值对进行保存,键为控件的Id,值为控件的引用,相信大家立刻就能想到Map;但是我们不用Map,因为有更好的替代类,就是我们android提供的SparseArray这个类,和Map类似,但是比Map效率,不过键只能为Integer.
import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
*构造一个通用的viewholder类
*
*/
public class ViewHolder {
private SparseArray<View> mViews;
private int mPosition;
private View mConvertView;
//layoutId即我们要引入的item布局文件的id
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);//引入我们的item布局文件
mConvertView.setTag(this);
}
//ViewHolder并不是每次都需要实例化,当convertview不为空时我们就不需要再实例化ViewHolder,因此我们增加一个入口方法
//来判断是否需要对ViewHolder实例化
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;
}
}
/**
* ͨ通过viewId获取控件,此方法返回的是View的一个子类
*/
public <T extends View> T getView(int viewId)
{
View view = mViews.get(viewId);
if (view == null) {
//如果mViews没有相应的控件,我们就从convertView中找到这个控件,并将此控件和其id存放在mViews中
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
//mConvertView的get方法
public View getConvertView() {
return mConvertView;
}
/**
* 找到我们定义的TextView控件,并给控件赋值
*/
public ViewHolder setText(int viewId, String text)
{
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
/**
* 如果item中有ImageView控件的话,我们就可以用此方法给控件设置图片资源
*/
public ViewHolder setImageResource(int viewId, int resId)
{
ImageView imageView = getView(viewId);
imageView.setImageResource(resId);
return this;
}
public ViewHolder setImageBitmap(int viewId, Bitmap bitmap)
{
ImageView imageView = getView(viewId);
imageView.setImageBitmap(bitmap);
return this;
}
//我们还可以添加其他的更多的方法。。。。。。。。。。。
}
分别可以通过setText()、setImageResource()、setImageBitmap() 来设置文字信息,图片
只看getView,其他方法都一样;首先调用ViewHolder的get方法,如果convertView为null,new一个ViewHolder实例,通过使用mInflater.inflate加载布局,然后new一个SparseArray用于存储View,最后setTag(this);如果存在那么直接getTag,最后通过getView(id)获取控件,如果存在则直接返回,否则调用findViewById,返回存储,返回。
3、创建Adapter基类
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* 编写通用的Adapter,指定泛型,以便适应不同的Java bean
* @param <T>
*/
public abstract class CommonAdapter<T> extends BaseAdapter {
//这些属性都是每个适配器中都能用到的,访问控制符设置为protected,以便继承的子类都能访问
protected LayoutInflater mInflater;
protected List<T> mDatas;//数据源
protected Context mContext;
protected int layoutId;//item布局文件
public CommonAdapter(Context context, List<T> mDatas, int layoutId) {
this.mContext = context;
this.mDatas = mDatas;
mInflater = LayoutInflater.from(context);
this.layoutId = layoutId;
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public T getItem(int position) {//这里的返回值类型是T,不是自动生成的Object
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
//初始化ViewHolder,加载我们的item布局文件
ViewHolder holder = ViewHolder.get(mContext, convertView, parent, layoutId, position);
convert(holder, getItem(position));//getItem(position)的类型就是T,这句话在子类中的具体实现就是给具体的控件初始化
//并赋值,初始化赋值控件时需要viewHolder和具体的数据Java bean,在这里抽象出来就是类型T
return holder.getConvertView();//返回convertView
}
public abstract void convert(ViewHolder holder, T t);
}