浅谈ListView之convertView和viewHolder

最近开发相册时,碰到缩略图显示的问题,功能实现后发现滚动时比较的卡顿,
先就ListView优化问题提出几点看法:
1、复用已经生成的convertView;
2、添加viewHolder类;
3、缓存数据(图片缓存);
4、分页加载。

1、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,就会大大改善性能。

<span style="background-color:rgb(204,204,204)">BaseAdapter适配器里有个getView()需要重写
public View getView(int position,View converView,ViewGroup parent)  {  //省略。。。。。。}</span>
这个convertView其实就是最关键的部分  原理上讲 当ListView滑动的过程中 会有item被滑出屏幕 而不再被使用 这时候Android会回收这个条目的view 这个view也就是这里的convertView。<pre name="code" id="best-content-1572584631" class="best-text mb-10" style="margin-top:0px; margin-bottom:10px; padding:0px; font-family:arial,'courier new',courier,宋体,monospace; white-space:pre-wrap; word-wrap:break-word; background-color:rgb(241,254,221)">当item1被移除屏幕的时候 我们会重新new一个View给新显示的item_new 而如果使用了这个convertView 我们其实可以复用它 这样就省去了new View的大量开销。

 

public View getView(int position, View convertView, ViewGroup parent) {
	View view = null;
	if (convertView != null) {
	view = convertView;
	//复用了回收的view 只需要直接作内容填充的修改就好了
	} else {
	view = new Xxx(...);
	//没有供复用的view 按一般的做法新建view
	}
	return view;
}

小demo:

static class ViewHolder
	{				
		public TextView mSelectAlbumName;
		public MyImageView mAlbumView;
		private TextView mImageCounts;
	}	
这里,static关键字的作用就是保证该类在内存中只有一个对象,也就是只有一块内存空间,所以不会ViewHolder holder = new ViewHolder()一次就会开辟一块新地址的,不管new几次,都是指向第一次new时开辟的地址,所有引用共用这一地址,即节省内存、又提高效率。


@Override
	public View getView(int position, View convertView, ViewGroup parent)
	{
	    final ViewHolder viewHolder;
	    String path = albumList.get(position).getPhotoList().get(0).getPath();
        if (convertView == null) 
        {   
        	viewHolder = new ViewHolder();
        	convertView = mInflater.inflate(R.layout.select_album_grid_item, null);		       	
        	viewHolder.mSelectAlbumName = (TextView)convertView.findViewById(R.id.txtSelectName);
        	viewHolder.mAlbumView = (MyImageView)convertView.findViewById(R.id.imgAlbum);    
        	viewHolder.mImageCounts = (TextView)convertView.findViewById(R.id.group_count);       	
        	viewHolder.mAlbumView.setOnMeasureListener(new OnMeasureListener() {
  				
  				@Override
  				public void onMeasureSize(int width, int height) {
  					mPoint.set(width, height);
  				}
  			});
        	convertView.setTag(viewHolder);            
        }  
        else { 
        	viewHolder = (ViewHolder) convertView.getTag(); 
        } 
		
        viewHolder.mSelectAlbumName.setText(albumList.get(position).getName());
        viewHolder.mImageCounts.setText(albumList.get(position).getCount()+" "+context.getString(R.string.pictures));
        viewHolder.mAlbumView.setTag(path);       
        Bitmap bitmap = ImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack()
        {
			@Override
			public void onImageLoader(Bitmap bitmap, String path) {			
			ImageView mImageView = (ImageView)mGridView.findViewWithTag(path); 
			if(bitmap != null && mImageView != null) {
				mImageView.setImageBitmap(bitmap);
			}
		   }
        });
        
        if(bitmap != null) {
        	 viewHolder.mAlbumView.setImageBitmap(bitmap);
        }
        return convertView; 
	}

2、 viewHolder类的使用

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

setTag()(设置标签)是将view封装起来,以便下次复用,getTag()(获取标签)是得到封装的view。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值