Android:ListView之ViewHolder


前言

  在開發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         @Override
14         public int getCount() {
15             return items.size();
16         }
17 
18         @Override
19         public Object getItem(int position) {
20             return items.get(position);
21         }
22 
23         @Override
24         public long getItemId(int position) {
25             return position;
26         }
27 
28         @Override
29         public boolean hasStableIds() {
30             return false;
31         }
32 
33         @Override
34         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         @Override
52         public int getItemViewType(int position) {
53             return 1;
54         }
55 
56         @Override
57         public int getViewTypeCount() {
58             return 1;
59         }
60 
61         @Override
62         public boolean isEmpty() {
63             return false;
64         }
65 
66         @Override
67         public boolean areAllItemsEnabled() {
68             return false;
69         }
70 
71         @Override
72         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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM