2015年5月18日星期一

优化ListView性能

As we all know, ListView的使用非常广泛,但是其也比较难用,难用之一就在于其有很多细节可以优化,故开此贴专门收集优化ListView性能的小方法。

1.convertView优化快速滚动效率

getView()中有一个名为convertView的参数,其用于将之前加载好的布局进行缓存,以便重用。上代码,

 @Override
 public View getView(int position, View convertView, ViewGroup parent){
  Fruit fruit = getItem(position);  //获取当前项的Fruit实例
  
  /*原方法,View view = LayoutInflater.from(getContext()).inflate(resourceId, null);*/
  
  /*使用convertView */
  View view;
  if (convertView == null){
   view = LayoutInflater.from(getContext().inflate(resourceId, null));
  }
  else{
   view = convertView;
  }
  
  ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
  TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
  fruitImage.setImageResource(fruit.getImageId());
  fruitName.setText(fruit.getName());
  return view;
 }

如代码注释,注释内的为原方法,每次getView都需要将布局重新加载一遍,当ListView快速滚动时会有性能障碍。

使用convertView方法后,首先判断convertView是否为空,若为空,使用LayoutInflater来加载布局;若不为空,直接对convertView进行重用。

LOL

2.ViewHolder对控件实例进行缓存

还是如上的代码中,我们发现,每次在getView()方法中都会调用view中的findViewById来获取一次控件的实例。

该ViewHolder闪亮登场了,直接上代码,

 @Override
 public View getView(int position, View convertView, ViewGroup parent){
  Fruit fruit = getItem(position);  //获取当前项的Fruit实例
  
  /*原方法,View view = LayoutInflater.from(getContext()).inflate(resourceId, null); */

  /*原方法,
                ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
  TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
  fruitImage.setImageResource(fruit.getImageId());
  fruitName.setText(fruit.getName());*/
  
  viewHolder.fruitImage.setImageResource(fruit.getImageId());
  viewHolder.fruitName.setText(fruit.getName());
  
  //使用convertView 

  View view;
  
  ViewHolder viewHolder;   
  
  if (convertView == null){
   view = LayoutInflater.from(getContext()).inflate(resourceId, null);
   //将ViewHolder存储在View中
   viewHolder = new viewHolder();
   viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
   viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
   view.setTag(viewHolder);   /*将ViewHolder存储在View中*/
  }
  else{
   view = convertView;
   viewHolder = (ViewHolder) view.getTag();  //重新获取ViewHolder
  }
  

  
  return view;
 }
 
 class ViewHolder{
  
  ImageView fruitImage;
  
  TextView fruitName;
 }


注意看新增的部分。

新建了一个内部类ViewHolder,用于对控件的实例进行缓存。

若convertView为空,创建ViewHolder对象,并将所有控件的实例都存在ViewHolder中,接着调用view的setTag()方法,将ViewHolder对象存放在view中;

若convertView不为空,调用view的getTag()方法,将ViewHolder重新取出。

因此,所有的控件实例都缓存在了ViewHolder中,不必如原方法般每次都通过findViewById来依次获取控件实例,从而优化了性能。么么哒。
LOL

没有评论:

发表评论