在看了一些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