大家在安卓开发过程中,经常会用到listview或者gridview,在编写代码的时候为了节约资源我们通常会采用持有者模式,即ViewHolder,如果一个工程中有多个listview,通常情况下我会写多个ViewHolder,还有多个adapter,每个adapter都要重写一遍里面的抽象方法,今天就教大家如何避免如此繁重的工作,能够一劳永逸。
首先我们先看一下传统适配器的写法。比如下面这段:
package com.jy.myadapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:03 */ public class OriginAdapter extends BaseAdapter{ private List<Bean> list; private Context mcontext; private LayoutInflater minflater; public OriginAdapter(List<Bean> list, Context mcontext) { this.list = list; this.mcontext = mcontext; minflater=LayoutInflater.from(mcontext); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolider holder; if(convertView==null){ holder=new ViewHolider(); convertView=minflater.inflate(R.layout.listitem,parent,false); holder.title= (TextView) convertView.findViewById(R.id.title); holder.dec= (TextView) convertView.findViewById(R.id.dec); holder.time= (TextView) convertView.findViewById(R.id.time); convertView.setTag(holder); }else{ holder= (ViewHolider) convertView.getTag(); } holder.title.setText(list.get(position).getTitlel()); holder.dec.setText(list.get(position).getDec()); holder.time.setText(list.get(position).getTime()); return convertView; } class ViewHolider{ TextView title; TextView dec; TextView time; } }
是不是很熟悉,当我们在开发多个listview的时候,都要对应不同的viewholder,所以我们可以考虑将viewholder封装起来,通过一个容器获取对应的view,提到容器,我们第一反应就是用map来存储键值对,其实在安卓中,还有一个类,叫做
SparseArray
在这个类里面有这么一段介绍,
It is intended to be more memory efficient
* than using a HashMap to map Integers to Objects
大概意思就是说它就相当于是hashmap,但是比hashmao效率更高,但是有一点要注意的是,SparseArray的键只能是integer类型!下面是我封装好了的一个ViewHolder类。
package com.jy.myadapter; import android.content.Context; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:38 */ public class ViewHolder { private SparseArray<View> mViews; private int mPosition; private View mConvertView; 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); mConvertView.setTag(this); } 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; } } public View getmConvertView() { return mConvertView; } /** * 根据id寻找控件 * @param viewid * @return */ public <T extends View> T getView(int viewid){ View view=mViews.get(viewid); if(view==null){ view=mConvertView.findViewById(viewid); mViews.put(viewid,view); } return (T) view; } /** * 为文本赋值 */ public void setText(int Viewid,String text){ TextView tv=getView(Viewid); tv.setText(text); } }
其其实看这段代码很熟悉,因为他的原理和我们之前写的是一样的,只不过这里进行了封装,仔细看的应该可以看明白。其中settext方法是给Textview进行赋值,当然,类似的,比如imageview等等,都可以在这里面添加对应的方法,我这里是拿Textview举例。封装好了ViewHolder之后,我们来看看怎么使用。下面这段代码就是使用封装好的ViewHolder的情况,主要看getview()方法中,是不是精简了不少?
package com.jy.myadapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import org.w3c.dom.Text; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:03 */ public class MydapterWithCommonViewHolder extends BaseAdapter{ private List<Bean> list; private Context mcontext; private LayoutInflater minflater; public MydapterWithCommonViewHolder(List<Bean> list, Context mcontext) { this.list = list; this.mcontext = mcontext; minflater=LayoutInflater.from(mcontext); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder=ViewHolder.get(mcontext,convertView,parent,R.layout.listitem,position); holder.setText(R.id.title,list.get(position).getTitlel()); holder.setText(R.id.dec,list.get(position).getDec()); holder.setText(R.id.time,list.get(position).getTime()); return holder.getmConvertView(); }
只需要五行代码。当然,这还不是最简单的,上面我说到,除了viewholder,在多个listview的情况下我们要编写多个adapter,每一个adapter都要重写多个抽象方法,那我们是不是也可以写一个通用的adapter,然后使用的时候继承这一个通用adapter
这样说很难理解,直接看代码,下面是一个通用的adapter
package com.jy.myadapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 16:26 */ public abstract class CommenAdapter<T> extends BaseAdapter{ protected Context mContext; protected List<T> mData; private LayoutInflater mInflater; private int layoutid; public CommenAdapter(Context context,List<T> datas,int layoutid) { this.mContext=context; this.mData=datas; this.layoutid=layoutid; mInflater=LayoutInflater.from(context); } @Override public int getCount() { return mData.size(); } @Override public T getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent){ ViewHolder holder=ViewHolder.get(mContext,convertView,parent,layoutid,position); convert(holder,getItem(position)); return holder.getmConvertView(); }; public abstract void convert(ViewHolder holder,T t); }
其中,conver这个抽象方法就是用来实现每个不同listview的不同处理逻辑,还是拿原来的adapter为例,继承自这个通用adapter,这样就不用重写那一连串方法。继承后的代码如下:
package com.jy.myadapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import org.w3c.dom.Text; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:03 */ public class MydapterWithCommonViewHolder extends CommenAdapter<Bean>{ public MydapterWithCommonViewHolder(List<Bean> data, Context context) { super(context,data,R.layout.listitem); } @Override public void convert(ViewHolder holder, Bean bean) { holder.setText(R.id.title,bean.getTitlel()); holder.setText(R.id.dec,bean.getDec()); holder.setText(R.id.time,bean.getTime()); } }
短短几行代码,就搞定了。
现在我们来对比一下前后的代码差距,一开始用我们通常的写法:
package com.jy.myadapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:03 */ public class OriginAdapter extends BaseAdapter{ private List<Bean> list; private Context mcontext; private LayoutInflater minflater; public OriginAdapter(List<Bean> list, Context mcontext) { this.list = list; this.mcontext = mcontext; minflater=LayoutInflater.from(mcontext); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolider holder; if(convertView==null){ holder=new ViewHolider(); convertView=minflater.inflate(R.layout.listitem,parent,false); holder.title= (TextView) convertView.findViewById(R.id.title); holder.dec= (TextView) convertView.findViewById(R.id.dec); holder.time= (TextView) convertView.findViewById(R.id.time); convertView.setTag(holder); }else{ holder= (ViewHolider) convertView.getTag(); } holder.title.setText(list.get(position).getTitlel()); holder.dec.setText(list.get(position).getDec()); holder.time.setText(list.get(position).getTime()); return convertView; } class ViewHolider{ TextView title; TextView dec; TextView time; } }
再看最后我们封装好的写法:
package com.jy.myadapter; import android.content.Context; import java.util.List; /** * User: juyao([email protected]) * Date: 2015-12-12 * Time: 15:03 */ public class MydapterWithCommonViewHolder extends CommenAdapter<Bean> { public MydapterWithCommonViewHolder(List<Bean> data, Context context) { super(context, data, R.layout.listitem); } @Override public void convert(ViewHolder holder, Bean bean) { holder.setText(R.id.title, bean.getTitlel()); holder.setText(R.id.dec, bean.getDec()); holder.setText(R.id.time, bean.getTime()); } }
是不是简单了很多!!!