ListView中convertView和ViewHolder的复用机制工作原理

最近碰到的面试题中经常会碰到问"ListView的优化"问题。所以就拿自己之前写的微博客户端的程序做下优化。
自己查了些资料,看了别人写的博客,得出结论,ListView优化大致从以下几个角度:
1.复用已经生成的convertView;
2.添加viewHolder类;
3.缓存数据(图片缓存);
4.分页加载。

一、复用convertView
首先讲下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。

ListView中convertView和ViewHolder的复用机制工作原理_第1张图片



图解:一个屏幕最多显示7个Item,如果当Item1滑出屏幕,此时Item1 的View被添加进Recycler中,相应的在下部要产生一个Item8,这时调用getView方法,convertView参数就是Item1 的View。


我们都知道在getView方法中的操作是这样的:先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder,把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。然后用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。当第二次重用convertView时,只需从convertView中getTag取出来就可以。

测试Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
  }





你可能感兴趣的:(ListView中convertView和ViewHolder的复用机制工作原理)