[color=red][size=medium][b]一、复用convertView[/b][/size][/color]
首先讲下ListView的原理:[color=red]ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。[/color]如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,[b]创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。[/b]Android提供了一个叫做Recycler([color=red]反复循环器[/color])的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。
一个屏幕最多显示7个Item,如果当Item1滑出屏幕,[color=red]此时Item1的View被添加进Recycler中[/color],相应的在下部要产生一个Item8,这时调用getView方法,convertView参数就是Item1的View。
[b][color=red](1)Item固定高度[/color][/b]
[b][color=red](2)Item高度不固定[/color][/b]
因为没有固定的Item高度,无法计算一个屏幕中能够显示的最大高度,系统会会先创建一个View,第一轮是用这个View来试探能放多少个item,试探出结果可以放3个Item,所以第二轮的0-2才是真正创建的View,屏幕上显示了3个Item。当往下滚时,Item0没有完全出去,下面有来了个Item3,所以这时的Item有创建了一个View,屏幕上此时显示4个Item。之后4个Item就是做多显示的数量,再往上滚动,convertView就开始重用了,Item4和Item0的View是一个对象。
[size=medium][b]二、使用ViewHolder类[/b][/size]
我们都知道在getView方法中的操作是这样的:[color=blue]先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。[/color][color=red]这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder[/color],把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。[color=red]然后用convertView的setTag将viewHolder设置到Tag中[/color],以便系统第二次绘制ListView时从Tag中取出。[color=red]当第二次重用convertView时,只需从convertView中getTag取出来就可以。[/color]
[size=medium][color=red]注意:缓存的是item中的layout布局文件信息 而不是列表内容[/color][/size]
首先讲下ListView的原理:[color=red]ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。[/color]如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,[b]创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。[/b]Android提供了一个叫做Recycler([color=red]反复循环器[/color])的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。
一个屏幕最多显示7个Item,如果当Item1滑出屏幕,[color=red]此时Item1的View被添加进Recycler中[/color],相应的在下部要产生一个Item8,这时调用getView方法,convertView参数就是Item1的View。
[b][color=red](1)Item固定高度[/color][/b]
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getView " + position + " " + convertView);
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.lv_item, null);
holder = new ViewHolder();
holder.textView = (TextView)convertView.findViewById(R.id.tv_text);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
return convertView;
}
[b][color=red](2)Item高度不固定[/color][/b]
因为没有固定的Item高度,无法计算一个屏幕中能够显示的最大高度,系统会会先创建一个View,第一轮是用这个View来试探能放多少个item,试探出结果可以放3个Item,所以第二轮的0-2才是真正创建的View,屏幕上显示了3个Item。当往下滚时,Item0没有完全出去,下面有来了个Item3,所以这时的Item有创建了一个View,屏幕上此时显示4个Item。之后4个Item就是做多显示的数量,再往上滚动,convertView就开始重用了,Item4和Item0的View是一个对象。
[size=medium][b]二、使用ViewHolder类[/b][/size]
我们都知道在getView方法中的操作是这样的:[color=blue]先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。[/color][color=red]这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder[/color],把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。[color=red]然后用convertView的setTag将viewHolder设置到Tag中[/color],以便系统第二次绘制ListView时从Tag中取出。[color=red]当第二次重用convertView时,只需从convertView中getTag取出来就可以。[/color]
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getView " + position + " " + convertView);
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.lv_item, null);
holder = new ViewHolder();
holder.textView = (TextView)convertView.findViewById(R.id.tv_text);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
return convertView;
}
}
public static class ViewHolder {
public TextView textView;
}
[size=medium][color=red]注意:缓存的是item中的layout布局文件信息 而不是列表内容[/color][/size]