Android:ListView之ViewHolder

來源:互聯網
上載者:User

前言

  在開發Android應用過程中經常要與列表展示打交道,比如Listview。在使用過程中如果不能正確的進行細節處理那麼對效能還是有很大的損耗的。

  Listview展示內容是通過一個Adapter來進行內容綁定的。如下所示:

  

 1 class Adapter implements ListAdapter{ 2  3         @Override 4         public void registerDataSetObserver(DataSetObserver observer) { 5              6         } 7  8         @Override 9         public void unregisterDataSetObserver(DataSetObserver observer) {10             11         }12 13         @Override14         public int getCount() {15             return items.size();16         }17 18         @Override19         public Object getItem(int position) {20             return items.get(position);21         }22 23         @Override24         public long getItemId(int position) {25             return position;26         }27 28         @Override29         public boolean hasStableIds() {30             return false;31         }32 33         @Override34         public View getView(int position, View convertView, ViewGroup parent) {35             ViewHolder vh =null;36             if(convertView==null){37                 vh = new ViewHolder();38                 convertView = mInflater.inflate(R.layout.item, null);39                 vh.tv = (TextView) convertView.findViewById(R.id.tvShow);40                 41                 convertView.setTag(vh);42             }else{43                 vh = (ViewHolder) convertView.getTag();44             }45             46             vh.tv.setText(items.get(position));47             48             return convertView;49         }50 51         @Override52         public int getItemViewType(int position) {53             return 1;54         }55 56         @Override57         public int getViewTypeCount() {58             return 1;59         }60 61         @Override62         public boolean isEmpty() {63             return false;64         }65 66         @Override67         public boolean areAllItemsEnabled() {68             return false;69         }70 71         @Override72         public boolean isEnabled(int position) {73             return true;74         }75         76 }

  有了這個Adapter就可以與Listview進行資料繫結了,如下所示:

  

lv.setAdapter(new Adapter());

  

getViw

在Adapter類中有一個重要的實現方法getView用來實現大部分的邏輯,這個就是這篇文章的重點。

public View getView(int position, View convertView, ViewGroup parent) {    ViewHolder vh =null;    if(convertView==null){        vh = new ViewHolder();        convertView = mInflater.inflate(R.layout.item, null);        vh.tv = (TextView) convertView.findViewById(R.id.tvShow);                convertView.setTag(vh);    }else{        vh = (ViewHolder) convertView.getTag();    }        vh.tv.setText(items.get(position));        return convertView;}

  先看下這個方法的官方解釋

  Get a View that displays the data at the specified position in the data set.
  You can either create a View manually or inflate it from an XML layout file.

  意思是說:擷取一個用來展示資料集中指定位置的資料的視圖。可以通過代碼或者inflate一個XML檔案來獲得這個View對象。

  Parameters(參數)
      position

      The position of the item within the adapter's data set of the item whose view we want.

      我們要展示的資料集中的資料條目的位置
      convertView
          The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using.
          If it is not possible to convert this view to display the correct data, this method can create a new view.
     Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount()and       getItemViewType(int)).

      一個能用就用的舊視圖。注意:在使用之前你需要去檢查這個視圖是否非空以及其類型。

      如果這個視圖不能用來正確展示資料,那麼此方法就需要建立一個新的視圖了。

      如果一個列表中有多種檢視類型,那麼也可以通過getViewTypeCount\getItemViewType方法來正確使用。
      parent     
          The parent that this view will eventually be attached to

      這個視圖要被添加到的對象

convertView

  上一段提到了convertView的reuse(重利用)的內容,也就是說在建立一個新視圖去返回給List 的時候需要先檢查下舊的視圖對象是否還可以利用,包括去檢查是否為空白以及類型是否正確等等。當然大部分情況下是可以利用的,因此通過這種方式就降低了每次去建立一個item 的view的效能開銷了。

  view能夠重複利用了,那麼view中的對象是不是也能夠重利用呢,比如其中的展示文本。當然,這就是這篇文章的標題提到的ViewHolder。

ViewHolder

  從字面上理解ViewHolder,a holder of the view,就是一個視圖的持有人,持有的內容就是視圖的所有指定內容,或者說是綁定內容(下面會提到綁定)。個人理解這個持有的意思,就好比是一個引用或者一個指標,ViewHolder中的內容發生了變化那麼對應的view中也會隨之發生變化;view中的內容發生了變化那麼ViewHolder中也隨之發生了變化。這就是所謂的hold吧。下面就看下如果綁定一個ViewHolder。

  先要定義一個ViewHolder對象,對象裡面的內容就是需要hold的視圖的內容,比如List中每一個item就是一個TextView用來展示資訊,那麼如下所示:

static final class ViewHolder{    TextView tv;}

  Item對象的XML,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="20dip" >    <TextView        android:layout_marginTop="5dip"        android:layout_marginBottom="5dip"        android:id="@+id/tvShow"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>

  ViewHolder中的tv就是用來hold  Item找那個的tvShow的。

  ViewHolder有了,那麼下面就進入綁定過程。還是回過頭來看下getView那個方法片段。

  

vh = new ViewHolder();convertView = mInflater.inflate(R.layout.item, null);vh.tv = (TextView) convertView.findViewById(R.id.tvShow);        convertView.setTag(vh);

  先把ViewHolder和convertView兩個對象建出來,然後通過vh.tv = (TextView) convertView.findViewById(R.id.tvShow);進行了綁定,這樣他們之間就產生了關聯。

  最後通過convertView.setTag(vh);方法使得View和ViewHolder產生了關聯,也就是vh真正成為了convertView這個View的holder。

  通過這樣的方式,以後如果重利用這個視圖,就可以通過vh = (ViewHolder) convertView.getTag();的方法來吧這個Holder拿出來,修改其中的內容就可以通過下面的方式了vh.tv.setText(items.get(position));

  這樣的話省去了findViwyById這樣的尋找,降低了開銷

 

後記:

  Listview有很多中最佳化效能的方式,這個算是其中一種。

 

完整代碼:ViewHolderDemo

 原文串連:http://www.cnblogs.com/luoaz/p/3734999.html

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.