您的位置:首页 > 其它

ListView之GeneralAdapter

2016-04-15 22:42 211 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: