2013-04-16 24 views
5

因此,使用通常熟知的ViewHolder模式如下(ListAdapter):關於ListView中ViewHolder模式實現優化

... 

    @Override 
    public View getView(final int position, View convertView, final ViewGroup parent) { 

     final Album album = albums.get(position); 

     ViewHolder viewHolder = null; 
     if (convertView==null){ 
      convertView = inflater.inflate(R.layout.albums_list_item, null); 

      final ImageView albumImage = (ImageView) convertView.findViewById(R.id.album_icon); 

      final TextView txtTitle = (TextView) convertView.findViewById(R.id.album_title); 

      final TextView txtDescription = (TextView) convertView.findViewById(R.id.album_copyright); 

      viewHolder = new ViewHolder(); 
      viewHolder.albumImage = albumImage; 
      viewHolder.txtTitle = txtTitle; 
      viewHolder.txtDescription = txtDescription; 
      convertView.setTag(viewHolder); 
     } 
     else 
      viewHolder = (ViewHolder)convertView.getTag(); 

     viewHolder.txtTitle.setText(album.getTitle(locale)); 
     viewHolder.txtDescription.setText(album.getCopyrightInfo(locale)); 
     ... 
     return convertView; 
    } 

而ViewHolder類通常是這樣的:

static class ViewHolder{ 
    public ImageView previewImage; 
    public TextView txtTitle; 
    public TextView txtDescription; 
} 

我的問題是關於ViewHolder的實現。
1)爲什麼不使用構造函數而不是初始化每個字段?
2)爲什麼它使用默認訪問類型而不是保護(實際上它必須是私有的,但這會影響性能,因爲由JIT創建的靜態訪問器)?那麼,我想它只是關於繼承。
那麼,爲什麼下面的模式是不是更好(不含「保護VS默認」訪問類型):

protected static class ViewHolder{ 
    public final ImageView previewImage; 
    public final TextView txtTitle; 
    public final TextView txtDescription; 

    public ViewHolder (final ImageView previewImage, final TextView txtTitle, final TextView txtDescription){ 
     this.previewImage = previewImage; 
     this.txtTitle = txtTitle; 
     this.txtDescription = txtDescription; 
    } 
} 

和ListAdapter唯一的變化是:

... 
final TextView txtDescription = (TextView) convertView.findViewById(R.id.album_copyright); 
viewHolder = new ViewHolder(albumImage, txtTitle, txtDescription); 
convertView.setTag(viewHolder); 
... 

反正它必須調用構造函數。這只是一個品味問題嗎?或者這個版本以某種方式變慢,或者以某種方式影響性能?

回答

2

我認爲它只是品味的主人。至於我,它甚至比標準的更好看。由於使用最終變量,您的版本可能會更快。

+0

謝謝,這就是我正在考慮的方式。 – Stan

1

在我看來,這是做這件事的最好方法,但有一些我會改變我的代碼。你在你的ViewHolder中有一個構造函數,你可以在其中設置視圖,但是我可以看到你沒有在你的代碼中使用它。我會使用它或只是刪除它。還有一件事anothet,居然有一個更好的方法來達到同樣的效果,但它只會在Android上工作4+:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 

    ImageView mIcon; 
    TextView mName; 
    if (convertView == null) { 
     convertView = LayoutInflater.from(context) 
      .inflate(R.layout.my_contact_listing, parent, false); 
     mIcon = (ImageView) convertView.findViewById(R.id.contact_icon); 
     mName = (TextView) convertView.findViewById(R.id.contact_name); 
     convertView.setTag(R.id.contact_icon, mIcon); 
     convertView.setTag(R.id.contact_name, mName); 
    } else { 
     mIcon = (ImageView) convertView.getTag(R.id.contact_icon); 
     mName = (TextView) convertView.getTag(R.id.contact_name); 
    } 

    Contact mContact = getItem(position); 
    mName.setText(mContact.getName()); 
    mIcon.setImageResource(mContact.getIcon()); 

    return convertView; 
} 
+0

謝謝。但是,它不使用ViewHolder視圖嗎? (「但是,因爲我可以看到你沒有在你的代碼中使用它): viewHolder.txtTitle.setText(album.getTitle(locale)); viewHolder.txtDescription.setText(album.getCopyrightInfo(locale)); – Stan

+0

的確,您可以使用視圖的setTag方法來實現此目的:http://developer.android.com/reference/android/view/View.html#setTag(int,java.lang.Object),以供參考。 – hardartcore

+0

你的意思是代碼行:convertView.setTag(viewHolder);?我沒有顯示這條線,因爲沒有比原來的更改。 ListAdapter中唯一的變化是ViewHolder的創建,它的字段初始化。 – Stan

5

我使用的方法非常相似,你的,但我把它一步,因爲ViewHolder對適配器類是私有的,所以我通過將視圖傳遞給構造函數並在其中設置值來將它緊緊地耦合到類,例如

private class ViewHolder 
    { 
     protected final ImageView image; 
     protected final TextView title; 
     protected final TextView status; 

     public ViewHolder(final View root) 
     { 
     image = (ImageView) root.findViewById(R.id.artist_image); 
     title = (TextView) root.findViewById(R.id.artist_title); 
     status = (TextView) root.findViewById(R.id.artist_status); 
     } 
    } 

而且在getView(...)

View row = convertView; 

    if (null == row || null == row.getTag()) 
    { 
    row = inflater.inflate(R.layout.adapter_artists, null); 
    holder = new ViewHolder(row); 
    row.setTag(holder); 
    } 
    else 
    { 
    holder = (ViewHolder) row.getTag(); 
    } 

,因爲它使我的適配器代碼getView(...)簡單,擁有最終變量的好處我喜歡做這種方式。我可能會得到一個小的速度提升,使其得到保護,但我發現即使在巨大的列表中,性能也是足夠的。

+3

但他們(機器人像Romain Guy這樣的開發人員)說,ViewHolder必須是靜態類(性能問題),如果它的外部類適配器使用私有訪問類型也是不好的想法(因爲它具有靜態的它不能爲內部的適配器)它必須比私有更寬(它們使用默認訪問類型,就像我上面提到的那樣)。 – Stan

+0

是的,我記得有關這方面的東西,我沒有一個很好的性能實驗。這是我想炫耀的構造函數模式,然後你會遇到確保沒有其他類在靜態時不能訪問它的問題。是否有足夠的靜態保護來完成這項工作? – ScouseChris

+0

最接近私人的訪問類型是受保護的,所以是的。我喜歡你的方法,現在改變我的代碼來使用它。它的代碼看起來沒有什麼區別。因爲它只是發送1參數而不是一堆參數。然而,它的耦合和內聚違反,但ViewHolder就像適配器的衛星級,所以它沒有什麼大不了的。 – Stan