ListView优化总结

ListView作为一个非常常用的组件,其流畅度对用户体验有着重要的影响。关于ListView的优化有各种形式,在此做一个总结记录,以供查询。

参考文章:

http://kohoh1992.github.io/PerformanceTipsForAndroidListView/

http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/

http://mzh3344258.blog.51cto.com/1823534/889879  

ListView源码


ListView的继承结构:



ListView是一个通过ListAdapter(Adapter子类)将数据与其绑定的可以垂直滚动的视图,ListAdapter为ListView提供数据以及相关信息,并为ListView生成每条数据对应的view。


优化ListView的核心就是尽可能的提高ListAdapter生成View的效率,即尽量使Adapter.getView()方法变的轻量。


ListView根据Adapter的getCount方法来获取列表需要绘制的子view数量(即item数量,每个item可以为简单的view或者复杂的viewgroup),然后开始逐条绘制item。绘制item对应的视图是由Adapter的getView方法来完成的, getView(intposition, ViewconvertView, ViewGroupparent),Adapter为每条数据生成对应的view。一个列表可能会有成千上万条数据,对应相同个数的view,但是屏幕上可以同时处于可见状态的view的数量却是有限的,因此ListView并没有为每条数据生成一个view,而是在列表滚动的过程中,将离开可视范围内的view进行了缓存复用,大大降低了需要生成的view的数量。其原理图如下:




因此,要优化ListView第一步就是使用系统提供的view的缓存,降低需要生成的view数量,这个缓存的view即getView方法中的convertView。

在每次调用getView方法生成view的时候,首先判断convertView是否可以复用,如果convertView为null,即缓存的view不存在,则创建新的view(通常通过inflate方法来进行),如果convertView存在,则直接使用。最后将数据填充到convertView即可。

public View getView(final int position, View convertView, ViewGroup parent) {
	      if (convertView == null) {
	        //没有可供复用的convertView的时候,通过inflate创建新的view
	    	convertView = mInflater.inflate(R.layout.list_item, null);
	      }
	       //convertView通过inflate方法,或者直接从缓存中复用过来后,申明其中的各个View
	       TextView fileName = (TextView)convertView.findViewById(R.id.tv_file_name);
	       ImageView icon = (ImageView)convertView.findViewById(R.id.iv_icon);
	       CheckBox checkBox = (CheckBox)convertView.findViewById(R.id.cb_choose_icon);
	       RelativeLayout  relativeLayout = (RelativeLayout) convertView.findViewById(R.id.rl_sd_file);
        
           //TODO 为其中的子view填充数据
        
	      return convertView;
	}

通过复用ListView缓存的convertView,我们可以极大的减少需要生成的view的数量,从而达到优化ListView的目的。


在每次调用getView方法的时候,除了创建view需要消耗大量的资源,我们每次还需要通过findViewById方法来寻找布局中的子view,并为其填充数据。在快速滑动ListView的时候,这个步骤将会消耗我们的资源和时间,尤其是在我们的view的布局非常复杂的情况下。此时,我们可以定义一个静态内部类,来对view的各个子view的引用进行保存,然后通过setTag方法将这个静态内部类的实例保存到view中,这样下次复用view的时候就可以直接通过getTag方法获取到这个静态内部类的实例,直接使用其中保存的引用就可以了,这样就可以避免重复的调用findViewById方法了。这种情况下只有在新建view的时候才需要使用findViewById方法了。

public View getView(int position, View convertView, ViewGroup parent) {
		 ViewHolder viewHolder;
	      if (convertView == null) {
	    	  viewHolder = new ViewHolder();
	    	  convertView = mInflater.inflate(R.layout.list_item, null);
	    	  viewHolder.fileName = (TextView)convertView.findViewById(R.id.tv_file_name);
	    	  viewHolder.icon = (ImageView)convertView.findViewById(R.id.iv_icon);
	    	  viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.cb_choose_icon);
	    	  viewHolder.relativeLayout = (RelativeLayout) convertView.findViewById(R.id.rl_sd_file);
	          convertView.setTag(viewHolder);
	      } else {
	    	  viewHolder = (ViewHolder) convertView.getTag();
	      }
	      
          //TODO 为view填充数据。。。      
	      viewHolder.mFileName.setText("position = " + position);
          //填充完毕
          
	      return convertView;
	}
	
	
	private static class ViewHolder {
		TextView  fileName;
		CheckBox checkBox;
		ImageView icon;
		RelativeLayout relativeLayout;
	}

在需要创建新的view的时候,我们一般通过inflate方法将xml布局文件加载进来,我们需要尽可能的将这个xml布局文件进行优化,以提高getView方法的效率。关于xml布局文件的优化,将集中再来一篇文章,小结一下

http://blog.youkuaiyun.com/u010483016/article/details/46042721


在ListView中加载图片资源是非常常见的一种情况,可能会加载本地的图片,也可能需要加载网络资源,而后一种情况更加的常见。在加载网络资源图片的时候,我们会通过异步加载的形式来避免对ui线程的阻塞,这样可以避免ANR问题以及带来流畅的用户体验。关于图片的加载以及异步加载图片,将集中小结一下。


未完待续



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值