ListView之GeneralAdapter

1、前言

        ListView的Adapter相信Android的小伙伴都非常的熟悉了,有很多人还会有一些很好的办法,看了很多优秀的这方面的文章,自己也有了一些自己的看法,这些想法多了,就会如梗在喉,不吐不快。

 2、概述

ListView是我们项目中最为常用的控件之一,它很好的贯彻了Java的一个类只做一件事的面向对象编程的思想,同时很好的诠释了JavaEE MVC编程思想,从这个方向理解,ListView就是MVC的V了,Adapter就是C,M嘛,就是我们的数据模型,至于是什么样的数据 ,就要看我们的业务逻辑了。

3、传统写法:

        我们知道,ListView要用到Adapter,ArrartAdapter与SimpleAdapter的使用网上有很多例子,基本思想都差不多,随便拿来改改就能用,这里不多做介绍。一般我们用的最多的就是自定义的Adapter,继承自BaseAdapter,这里就从这个地方谈起。

         BaseAdapter是一个Abstract类,这有三个方法必须复写,别是public int getCount(),public Object getItem(int position),public long getItemId(int position),public View getView(int position, View convertView, ViewGroup parent);

    (1)没有优化的例子:

public class MyAdapter extends BaseAdapter{

	private Context mContext;
	private List<String> mDatas;
	private int mItemLayoutid;
	
	public MyAdapter(Context mContext, List<String> mDatas, int mItemLayoutid) {
		super();
		this.mContext = mContext;
		this.mDatas = mDatas;
		this.mItemLayoutid = mItemLayoutid;
	}

	@Override
	public int getCount() {
		// TODO 自动生成的方法存根
		return mDatas.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO 自动生成的方法存根
		return mDatas.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO 自动生成的方法存根
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
			convertView = LayoutInflater.from(mContext).inflate(mItemLayoutid, parent,false);
			TextView  textview = (TextView) convertView.findViewById(R.id.item_textview);
			textview.setText(mDatas.get(position));
		return convertView;
	}
}
以上代码在getView中每次调用都会从xml资源中去加载一个view,并找出里面的控件,然后给这个控件进行赋值,这样的写法是可以运行的,如果数据量小的话,也没有什么问题,但是google官方给出更好的实现:

(2)优化的例子:

public class MyAdapter extends BaseAdapter{

	private Context mContext;
	private List<String> mDatas;
	private int mItemLayoutid;
	
	public MyAdapter(Context mContext, List<String> mDatas, int mItemLayoutid) {
		super();
		this.mContext = mContext;
		this.mDatas = mDatas;
		this.mItemLayoutid = mItemLayoutid;
	}

	@Override
	public int getCount() {
		// TODO 自动生成的方法存根
		return mDatas.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO 自动生成的方法存根
		return mDatas.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO 自动生成的方法存根
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder viewholder = null;
		if(convertView == null){
			viewholder = new ViewHolder();
			convertView = LayoutInflater.from(mContext).inflate(mItemLayoutid, parent,false);
			viewholder.mItemContent = (TextView) convertView.findViewById(R.id.item_textview);
			convertView.setTag(viewholder);
		}else{
			convertView = (View) convertView.getTag();
		}
		viewholder.mItemContent.setText(mDatas.get(position));
		return convertView;
		
	}
	
	class ViewHolder{
		private TextView mItemContent;
	}

}
以上的代码中,用一个ViewHolder类来承载了你用xml写的view,注意我用了承载这个词,因为我找不到更好的词可以在这个地方拿来用,反正基本意思就是这个ViewHolder代表了你的View,其实在内存里,这个ViewHolder中的字段指向的和View是同一块内存,所以我们给Viewholder的实例赋值,也就是给你要返回的View中的字段(或属性)赋值,其本质是一样的。

4、进一步思考:

上面的代码的确可以使用,并且也是Google推荐的做法,也是很容易理解的代码,但是写多了,就会觉得代码量很大,且很多都 是一样的代码,这不符合程序员的一惯的懒惰的优良作风。那上面的代码又有什么问题呢?最起码有下面的几个问题:

  (1)Context在这里起的作用是必须的吗?

  (2)传进去的数据只能是String类型(写死的)

那怎么来解决这些问题呢?请看下面的例子:

public  class GeneralListViewAdapter<T> extends BaseAdapter {
	
	private List<T> mListDatas = null;
	private IItemViewHolder mIViewHolder;
	private int  mItemLayoutId;
	//private ItemContent<T> mItemContent;
    
	public GeneralListViewAdapter(int itemlayoutid,List<T> listdatas,IItemViewHolder iviewholder) {
		mListDatas = listdatas ;
		mIViewHolder = iviewholder;
		mItemLayoutId =itemlayoutid;
	}
	@Override
	public int getCount() {
		return mListDatas.size();
	}
	@Override
	public T getItem(int position) {
		return mListDatas.get(position);
	}
	@Override
	public long getItemId(int position) {
		return position;
	}
	@Override
	public View getView(int position, View convertview, ViewGroup parent) {
		if (convertview == null || convertview.getTag() == null) {
			try {
				mIViewHolder = mIViewHolder.getClass().newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			convertview = LayoutInflater.from(parent.getContext()).inflate(mItemLayoutId, parent,false);
			mIViewHolder.bindToItemView(convertview);
			convertview.setTag(mIViewHolder);
		} else{
			mIViewHolder = (IItemViewHolder) convertview.getTag() ;
		}
		    mIViewHolder.updataItemContent(getItem(position));
		return convertview;
	}
	
	public interface IItemViewHolder {
		public abstract <T> void updataItemContent(T itemdata);
		public abstract void bindToItemView(View itemview);
	}
}
以上代码我们将不变部分进行了封装,变化的部分抽取成了接口。同时解决了上面的问题:Context实例我们通过传进来的父控件来获取,不再需要传递进来,传进的数据我们用泛型,并用在updataItemContent(T itemdata)方法中传出,这样,我们在写代码的时候只需要实现这个接口就行了,接口的两个方法也很好理解:一个是把自己绑定到View,一个是给view的属性更新数据。只需要这么多就行了,如果你觉得这样难以理解,写成这样可能更符合原来的思维方式吧!

public abstract class GeneralListViewAdapter<T> extends BaseAdapter {
	
	private List<T> mListDatas = null;
	private IItemViewHolder mIViewHolder;
	private int  mItemLayoutId;
	//private ItemContent<T> mItemContent;
    
	public GeneralListViewAdapter(int itemlayoutid,List<T> listdatas,IItemViewHolder iviewholder) {
		mListDatas = listdatas ;
		mIViewHolder = iviewholder;
		mItemLayoutId =itemlayoutid;
	}
	@Override
	public int getCount() {
		return mListDatas.size();
	}
	@Override
	public T getItem(int position) {
		return mListDatas.get(position);
	}
	@Override
	public long getItemId(int position) {
		return position;
	}
	@Override
	public View getView(int position, View convertview, ViewGroup parent) {
		if (convertview == null || convertview.getTag() == null) {
			try {
				mIViewHolder = mIViewHolder.getClass().newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			convertview = LayoutInflater.from(parent.getContext()).inflate(mItemLayoutId, parent,false);
			bindToItemView(convertview);
			convertview.setTag(mIViewHolder);
		} else{
			mIViewHolder = (IItemViewHolder) convertview.getTag() ;
		}
		    updataItemContent(getItem(position));
		return convertview;
	}
	
	public interface IItemViewHolder {
//		public abstract <T> void updataItemContent(T itemdata);
//		public abstract void bindToItemView(View itemview);
	}
	public abstract <T> void updataItemContent(T itemdata);
	public abstract void bindToItemView(View itemview);
}

当然上面的代码只是一个简单的抽象和抽取,其实ListView还有很多可以优化的地方,比如,就像ListView与Adapter之间的观察者模式,其实我们可以做成让Adapter再做一回观察者,数据源做被观察者,这样就可以实现只要数据变化了,ListView就会自动更新,下一篇将实现上述能够自动更新的ListView

本文资源下载:点击打开链接:http://download.csdn.net/detail/xinxincement/9492966

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@cement

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值