ListView - 如何提高執行效能
在 ListView 中,如何有效的提高執行效能是很重要的一點,它有相當多的細節可以優化,這邊會介紹該如何去提高執行的效能。
佈局緩存
在沒有做佈局緩存的時候,我們的 ListView 的執行效率是非常耗時的,因為在 getView()
的方法中,每次都將佈局重新載入了一次,當 ListView 快速的上下滾動時,這邊就會造成效能的低弱。
在 getView()
中有一個 convertView
參數,這個參數會將之前加載好的佈局進行緩存,以便之後進行重用。我們試著修改原本的 FruitAdapter
中的 getView()
代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; }
@Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view; if( convertView == null ) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); } else { view = convertView; }
ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; } }
|
這樣的話,每次在 getView()
中就會先去判斷是不是有加載的佈局,如果沒有的話會使用 LayoutInflater
去加載佈局,如果有的話,直接使用已加載好的 convertView
。這樣可以在快速滾動的時候展示出更好的效能。
ViewHolder
雖然現在已經不會每次都加載佈局,但是我們每次在 getView()
中還是會呼叫 View
的 findViewById()
來獲取元件的一次實體。這邊我們可以用一個 ViewHolder
針對這部份進行優化,繼續修改代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view; ViewHolder viewHolder; if( convertView == null ) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); viewHolder = new ViewHolder(); viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image); viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name); view.setTag(viewHolder); } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); }
viewHolder.fruitImage.setImageResource(fruit.getImageId()); viewHolder.fruitName.setText(fruit.getName()); return view; }
class ViewHolder { ImageView fruitImage; TextView fruitName; }
|
我們新增了一個 ViewHolder
,將元件的實體進行緩存,當 convertView
為 null
的時候,創建一個 ViewHolder
的實體,並將元件存放在 ViewHolder
裡,然後使用 setTag()
方法, 將 ViewHolder
實體存在 View
中, 當 convertView
不為 null
的時候,利用 getTag()
將 ViewHolder
重新取出, 這樣所有的元件實體都緩存在 ViewHolder
裡, 就沒必要每次透過 findViewById()
獲取元件了。