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);

}





原文地址:https://www.cnblogs.com/vegetate/p/9997303.html