本篇文章你会了解以下内容:
1、抽取ViewHolder,实现优化第一步
2、抽取公共Adapter,告别冗余方法
3、控件直接赋值,让Adapter再次优化
执笔不易,觉得不错,请转发分享(更多Android文章,还请关注左侧栏中我的公众号)。
ListView不得不说是Android开发当中出现率相当高的一个控件,什么资讯列表,联系人列表,消息列表等等,无不有它的身影存在。既然项目中有太多的地方会用到它,传统的代码逻辑我们是怎么使用的呢?每写一个ListView,都要去写一个Adapter类,一个ViewHolder类,这几乎是我们必须要操作的,以致于有太多太多的冗余代码,让我们感到真的不厌其烦,一个两个还可以,十个八个,就真的有点太崩溃了,不仅代码繁琐,还会占用内存,为了解决这样的一个问题,下面就要开始对其抽取优化,代码之间从上到下进行衔接,不要跳过看啊。
1、抽取ViewHolder,实现优化第一步
我们知道正常的ViewHolder,会在Adapter的getView方法里去操作很多事情,创建实例,赋值控件,setTag和getTag等,如下代码所示,是我们最常用的模式,这里我只用了两个控件,其实开发中有很多的View,对ViewHolder的优化,就是把这些代码封装进行抽取。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = View.inflate(mContext, R.layout.item_view, null);
viewHolder = new ViewHolder();
viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_title);
viewHolder.tvContent = (TextView) view.findViewById(R.id.tv_content);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.tvTitle.setText(mDatas.get(position).getTitle());
viewHolder.tvContent.setText(mDatas.get(position).getContent());
return view;
}
private static class ViewHolder {
TextView tvTitle, tvContent;
}
自定义一个ViewHolder类,实现构造方法,既然要实现对以上的代码进行一个抽取,那么getView里的参数,ViewHolder类大部分都需要用到,在ViewHolder类中,写一个静态方法,用于获取ViewHolder,其判断逻辑和以上代码思路一致,convertView若不存在就去创建ViewHolder,若存在就复用。
public static ViewHolder getViewHolder(Context context, int position,
View convertView, ViewGroup parent, int layoutId) {
if (convertView == null) {
return new ViewHolder(context, position, parent, layoutId);
} else {
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mPosition = position;
return viewHolder;
}
}
实现其构造方法,用于convertView不存在时进行对其实例:
private SparseArray
private int mPosition;
private View mConvertView;
public ViewHolder(Context context, int position, ViewGroup parent, int layoutId) {
mPosition = position;
mView = new SparseArray
mConvertView = View.inflate(context, layoutId, null);
mConvertView.setTag(this);
}
mView是用于存储各个控件View,在这里为什么要用SparseArray而不用Map,我们可以去查看下源码,其实对于键为int类型,SparseArray要比map更加有效的使用内存。
mPosition是记录索引位置。
mConverView就是创建的View对象,注意看上述代码,它是在convertView为null的情况下,才去创建的。
写一个方法,用于通过ViewHolder来获取各个控件:
public <T extends View> T getView(int layoutId) {
View view = mView.get(layoutId);
if (view == null) {
view = getmConvertView().findViewById(layoutId);
mView.put(layoutId, view);
}
return (T) view;
}
再写一个获取layout的方法:
public View getmConvertView() {
return mConvertView;
}
经过以上代码,对于ViewHolder,我们基本上就抽取完成了,回过来,我们再看adapter里的getView方法(注意,原来adapter里的ViewHolder类可以对其删除),是不是一下整洁了许多。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder=ViewHolder.getViewHoder(mContext,position,
convertView,parent,R.layout.item_view);
((TextView)viewHolder.getView(R.id.tv_title)).
setText(mDatas.get(position).getTitle());
((TextView)viewHolder.getView(R.id.tv_content)).
setText(mDatas.get(position).getContent());
return viewHolder.getmConvertView();
}
2、抽取公共Adapter,告别冗余方法
ViewHolder抽取完之后,省去了太多的代码,但是我们会发现Adapter里除了getView方法,其它三个也是重复的,那么接下来,我们就对Adapter进行抽取优化,新建一个万能的Adapter类,继承于BaseAdapter,记住要是抽象的,把getView方法设成抽象方法,这样其它Adapter继承这个万能Adapter,只需要重写getView方法即可。
public abstract class UniversalAdapter<T> extends BaseAdapter {
protected List<T> mDatas;
protected Context context;
private int layoutId;
public UniversalAdapter(Context context, List<T> mDatas, int layoutId) {
this.mDatas = mDatas;
this.context = context;
this.layoutId = layoutId;
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public Object getItem(int position) {
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
}
在上述代码中,细心的同志的可能看到了,实现其构造方法时,我传入了一个layoutId,其实就是一个XML资源,引入它,说白了,在getView方法里我连 ViewHolder viewHolder=ViewHolder.getViewHolder(mContext,position,convertView,parent,R.layout.item_view);这段代码我也不想去写,怎么办呢?很简单getView方法不去抽象化,而引出一个抽象的方法,具体可以改成以下方式:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHoder = ViewHolder.getViewHolder(context, position, convertView, parent, layoutId);
convert(viewHolder, mDatas.get(position));
return viewHolder.getmConvertView();
}
protected abstract void convert(ViewHolder viewHolder, Object item);
以后我们所有的Adapter继承这个万能的Adapter之后,只需要重写convert这个方法就好了,Object item是一个Bean,获取时要进行强转。
public class MyAdapter extends CourAdapter {
public MyAdapter(List
super(context, data, layoutId);
}
@Override
protected void convert(ViewHoder viewHoder, Object item) {
((TextView)viewHolder.getView(R.id.tv_title)).
setText(((Bean)item).getTitle());
((TextView)viewHolder.getView(R.id.tv_content)).
setText(((Bean)item).getContent());
}
}
看看以上的代码,是不是就简单了很多呢。
3、控件直接赋值,让Adapter再次优化
经过以上的优化之后,代码大大的减少了,但是,我还想进行对其优化,也就是说,我连setText都不想去那么麻烦,这样的话,我们就是可以在ViewHolder这个类中去写控件赋值方法:
//TextView设置数据
public ViewHolder setText(int viewId, String txt) {
TextView mTextView = getView(viewId);
mTextView.setText(txt);
return this;
}
再看convert方法,是不是又一下简单的很多。
@Override
protected void convert(ViewHolder viewHolder, Object item) {
viewHolder.setText(R.id.tv_title,((Bean)item).getTitle())
.setText(R.id.tv_content,((Bean)item).getContent());
}
当然了对于其它控件你也可以这样去做,比如ImageView:
public ViewHolder setPic(int viewId, String url) {
ImageView mImageView = getView(viewId);
//ImageLoader.getInstance().loadImage(url,mImageView);
return this;
}
好了同志们,以上就是今天分享的所有内容,更多Android文章还请关注左侧栏中我的微信公众号,好累啊,拜拜了。