使用ListView不可避免的要重写Adapter的getView(int position, View convertView, ViewGroup parent)方法,为了减少资源消耗,要使用convertView复用机制;为了提高系统性能,常用ViewHolder机制。
所谓的convertView复用机制是指getView方法返回的(return)是否为convertView,如果该方法的返回值都是通过LayoutInflater填充得到的,即每一个itemView都是现用现造,势必增加资源消耗;作为每次调用都能够获取到的convertView,它本身就是一个View类型的参数。我们可以将其按条件赋值,若其为空,就使用LayoutInflater进行填充,否则就直接使用。这样的话使用LayoutInflater进行填充的次数仅仅等于屏幕能够展示的item的个数,则能明显降低资源消耗,提高复用率。
所谓的ViewHolder机制就是在1:自定义Adapter中定义VeiwHolder内部类,2:该内部类中含有item布局文件中需要根据数据源展示的控件变量,如“TextView,ImageView”等,它的主要作用是依附于convertView,减少从convertView中寻找控件变量的次数。做法是3:在getView方法中持有ViewHolder类型的局部变量,4:若convertView为空,5:则new出ViewHolder对象让其指向ViewHolder类型的局部变量,6:并将通过LayoutInflater7:填充得到的convertView中的对应控件变量依次赋值给VeiwHolder对象,8:之后将ViewHolder对象设置为convertView的Tag;9:若convertView不为null,10:则只需拿到convertView的Tag,强制转换为VeiwHolder类型并赋值给ViewHolder类型的局部变量。
文字太多看花眼了是吧,下面拿代码说话。
public class CommentAdapter extends BaseAdapter { //成员变量 List<String> list; //数据源 Context context;//作为LayoutInflater.from()的参数 //构造方法 public CommentAdapter(List<String> list, Context context) { this.list = list; this.context = context; } //方法重写 @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(final int position, View convertView, ViewGroup parent) { //3在getView方法中持有ViewHolder类型的局部变量 final ViewHolder holder; if (convertView == null) {//4若convertView为空, //5则new出ViewHolder对象让其指向ViewHolder类型的局部变量 holder = new ViewHolder(); //6并将通过LayoutInflater填充得到的convertView convertView = LayoutInflater.from(context).inflate(R.layout.your_item_layout, null); //7填充得到的convertView中的对应控件变量依次赋值给VeiwHolder对象 holder.mTv = (Textview)convertView.findViewById(R.id.your_textview_id); //8之后将ViewHolder对象设置为convertView的Tag convertView.setTag(holder); } else {//9若convertView不为null, //10则只需拿到convertView的Tag,强制转换为VeiwHolder类型并赋值给ViewHolder类型的局部变量。 holder = (ViewHolder) convertView.getTag(); } //holder.mTv.setText(list.get(position)); //以及其他控件变量需要完成的逻辑 return convertView; } //1在自定义Adapter中定义VeiwHolder内部类 class ViewHolder { //2该内部类中含有item布局文件中需要根据数据源展示的控件变量,如“TextView,ImageView”等 Textview mTv; } }
以上说的想必大家都能明白,下面重点来了。
有时候,代码与故事有着惊人的相似之处啊。getView方法就好比西天取经这件事,佛祖(系统)的最终目的是见到唐僧(convertView),但唐僧若想取得真经必须经过一番磨炼(控件变量需要完成的逻辑),由于路途遥远、妖怪众多,唐僧(convertView)需要一个随从悟空(holder)。
- 当唐僧还没有出生的时候:convertView == null
- 悟空已经出世:holder= new ViewHolder()
- 接着金蝉子转世变为唐僧:convertView=LayoutInflater.from(context).inflate(R.layout.your_item_layout, null)
- 师徒相遇
- 唐僧需要处理不同的事情,比如化斋,牵马:(Textview)convertView.findViewById(R.id.your_textview_id) (Imageview)convertView.findViewById(R.id.your_imageview_id)
- 唐僧教会了悟空处理上述事情:holder.mTv = (Textview)convertView.findViewById(R.id.your_textview_id)
- 唐僧得到了紧箍咒,从此便占悟空为己有:convertView.setTag(holder)
- 一路上唐僧没少念紧箍咒折磨悟空,让悟空明白自己就是一个跟班的,再也不是当初的齐天大圣了:holder = (ViewHolder) convertView.getTag()
- 但凡遇到悟空会做的事情,唐僧便来一句,悟空,你去做吧!:holder.mTv.setText(list.get(position))
- 唐僧修成正果,面见我佛:return convertView