Android ListView优化实践

在看了一些vogella的文章以后,发现关于android listview性能优化这一段颇有意思,因而实践了一下,通过优化,性能确实提高很多! html

先看看优化前和优化后的比较: java

优化前的log截图: android

优化后的log截图: 性能优化

而且,在不停滚动ListView的过程当中,优化以前会出现ANR现象,在AVD上特别容易复现: 数据结构

而后,优化后显得很流畅,附上对于的log截图: ide

下面附上相关代码分析: 布局

ListView中的每个Item由一个ImageView 和一个TextView组成 性能

Layout: 测试

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal" >
        
        <ImageView android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent" />"
        <TextView android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_marginLeft="15dp"
            android:gravity="center_vertical" />
</LinearLayout>


Activity继承自ListActivity,我故意增长了Item,方便测试,效果更明显: 优化

public class ListViewDemo extends ListActivity{

	private final String[] mItems = new String[] { "Android", "iPhone",
			"WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			"Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu",
			"Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7",
			"Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X",
			"Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2" };
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		ListViewArrayAdapter adapter = new ListViewArrayAdapter(this, mItems);
		getListView().setAdapter(adapter);
	}
}


而后custom Adapter,优化以前的adapter:

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		long start = System.currentTimeMillis();
		LayoutInflater inflater = (LayoutInflater) mContext.getLayoutInflater();
		View rowView = inflater.inflate(mViewResourceId, parent, false);
		TextView textView = (TextView) rowView
				.findViewById(mTextViewResourceId);
		ImageView imageView = (ImageView) rowView
				.findViewById(mImageViewResourceId);
		textView.setText(mNames[position]);
		String s = mNames[position];
		if (s.startsWith("Windows7") || s.startsWith("iPhone")) {
			imageView.setImageResource(R.drawable.no);
		} else {
			imageView.setImageResource(R.drawable.yes);
		}
		    
		Log.v("jerikc","cost time = " + (System.currentTimeMillis() - start));
		return rowView;
	}


优化以后的Adapter:

public class ListViewArrayAdapter extends ArrayAdapter<String>{

	private final Activity mContext;
	private final String[] mNames;
	private final static int mViewResourceId = R.layout.text_image_row_layout;
	private final static int mTextViewResourceId = R.id.textView;
	private final static int mImageViewResourceId = R.id.imageView;
	static class ViewHolder {
		public TextView text;
		public ImageView image;
	}
	
	public ListViewArrayAdapter(Activity context, String[] names) {
		super(context, mViewResourceId, names);
		this.mContext = context;
		this.mNames = names;
	}
	
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		long start = System.currentTimeMillis();
		View rowView = convertView;
		if (rowView == null) {
			LayoutInflater inflater = mContext.getLayoutInflater();
			rowView = inflater.inflate(mViewResourceId, null);
			ViewHolder viewHolder = new ViewHolder();
			viewHolder.text = (TextView) rowView.findViewById(mTextViewResourceId);
			viewHolder.image = (ImageView) rowView.findViewById(mImageViewResourceId);
			rowView.setTag(viewHolder);
		}
		
		ViewHolder holder = (ViewHolder) rowView.getTag();
		String s = mNames[position];
		holder.text.setText(s);
		if (s.startsWith("Windows7") || s.startsWith("iPhone")) {
			holder.image.setImageResource(R.drawable.no);
		} else {
			holder.image.setImageResource(R.drawable.yes);
		}
		    
		Log.v("jerikc","cost time = " + (System.currentTimeMillis() - start));
		return rowView;
	}
}


优化的大体思想就是:优化以前,每次加载item的时候,都要加载一下布局文件,而后生成一个新的row View对象,而后经过View找到对应的ImageView和TextView,正如咱们所知道的那样,加载布局文件时很耗时的,特别是在操做比较频繁状况下,这是不可忍受的,因此会致使ANR现象。

所以,咱们能够重复利用已不可见的row View对象。Android中,当它决定让row View对象不可见的时候,它容许经过getView方法中的convertView参数来重复利用刚刚不可见的row View对象。

在优化的过程当中,第一次加载的时候,咱们须要把相关的数据保存起来,而View有一个方法setTag,该方法可用来保存一些数据结构。咱们一个row View对象是由ImageView和TextView空间组成的,所以定义一个ViewHolder来保存ImageView和TextView对象。在重复利用的过程当中,只需简单修改它们的值,而不用再次findViewById

关于findViewById耗时的分析,可参考:

http://www.cnblogs.com/over140/archive/2011/03/23/1991100.html

相关文章
相关标签/搜索