Android性能优化之ListView缓存机制

要想优化ListView首先要了解它的工做原理,列表的显示需要三个元素:ListView、Adapter、显示的数据。java

这里的Adapter就是用到了适配器模式,不管传入的是什么View在ListView中都能显示出来。android


如下简单说下上图的原理:

一、假设你有几千几万甚至不少其它的选项(item)时。当中仅仅有可见的项目(满屏显示的Item数目)存在内存(说的优化就是说在内存中的优化!)中,其它的在Recycler中缓存

二、ListView先请求一个type1视图(getView)而后请求其它可见的项目。convertView在getView中是空(null)的。第一次都是为空的。仅仅要显示过了convertView都不为空,会保存在Recycler中app

三、当item1滚出屏幕。并且一个新的项目从屏幕低端上来时。ListView再请求一个type1视图。ide

convertView此时不是空值了,它的值是item1。你仅仅需设定新的数据而后返回convertView,没必要又一次建立一个视图,省去了inflate和findViewById的时间,性能就获得了优化。函数


了解了它的工做原理后,咱们就可以反复利用convertView,仅仅要不为空就直接使用。改变它的内容便可了。性能

使用ListView的时候都会搭配一个Adapter,为了使得性能更优。ListView会缓存行item(某行相应的View)。ListView经过Adapter的getView函数得到每行的item。
优化

package com.dzt.listviewdemo;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

	private ListAdapter adapter;
	private ListView lv = null;
	private ArrayList<String> list = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		lv = (ListView) findViewById(R.id.lv_list);
		adapter = new ListAdapter();
		for (int i = 0; i < 100; i++) {
			list.add("item " + i);
		}
		lv.setAdapter(adapter);
	}

	private class ListAdapter extends BaseAdapter {

		private LayoutInflater mInflater;

		ListAdapter() {
			mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return list.get(position);
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// TODO Auto-generated method stub
			System.out.println("getView " + position + "    " + convertView);
			viewHolder holder = null;
			if (convertView == null) {
				convertView = mInflater.inflate(R.layout.item, null);
				holder = new viewHolder();
				holder.text = (TextView) convertView.findViewById(R.id.tv_text);
				holder.image = (ImageView) convertView
						.findViewById(R.id.iv_img);
				convertView.setTag(holder);
			} else {
				holder = (viewHolder) convertView.getTag();
			}
			holder.text.setText(list.get(position));
			if (position % 2 == 0) {
				holder.image.setImageResource(R.drawable.ic_launcher);
			} else {
				holder.image.setImageResource(R.drawable.icon);
			}

			return convertView;
		}

	}

	/**
	 * 使用一个类来保存Item中的元素
	 * 
	 * @author Administrator
	 * 
	 */
	public static class viewHolder {
		public TextView text;
		public ImageView image;
	}
}
执行效果


第一次打印的结果convertView都是为null.net


滑动ListView后的打印对象


从上面的打印消息可以看出,Recycler中会保存七个convertView对象用来显示Item。不管你有上千个Item,也仅仅会建立显示满屏的convertView。这就大大节省了内存,对viewHolder的Tag的使用也大大节省了性能开销

相关代码下载:http://download.csdn.net/detail/deng0zhaotai/7842885