2013-04-16 27 views
5

Vì vậy, các ViewHolder mẫu nổi tiếng sử dụng thường trông giống như (ListAdapter):Về ViewHolder thực hiện mô hình tối ưu hóa trong ListView

... 

    @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; 
    } 

trong khi lớp ViewHolder thường trông giống như:

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

Câu hỏi của tôi là về việc triển khai ViewHolder.
1) Tại sao nó không sử dụng một hàm tạo thay vì khởi tạo mọi trường đơn?
2) Tại sao nó sử dụng kiểu truy cập mặc định thay vì được bảo vệ (thực ra nó phải là riêng tư nhưng hiệu suất tác động này do các trình truy cập tĩnh được tạo bởi JIT)? Vâng, tôi đoán nó chỉ thừa kế thôi.
Vậy tại sao mô hình sau đây không phải là tốt hơn (không bao gồm "bảo vệ vs mặc định" loại truy cập):

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; 
    } 
} 

và sự thay đổi duy nhất ở ListAdapter là:

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

Dù sao nó phải gọi một constructor. Nó chỉ là vấn đề của hương vị? Hoặc là phiên bản này chậm hơn bằng cách nào đó hoặc nó có tác động đến hiệu suất theo một cách nào đó không?

Trả lời

2

Tôi nghĩ rằng đó chỉ là sở thích của hương vị. Đối với tôi nó thậm chí còn tốt hơn sau đó một tiêu chuẩn. Ngoài ra phiên bản của bạn có thể sẽ có khả năng nhanh hơn vì sử dụng các biến cuối cùng.

+0

Cảm ơn, đó chỉ là cách tôi đang nghĩ về nó. – Stan

1

Theo tôi đây là cách tốt nhất để làm điều đó, nhưng có điều gì đó mà tôi sẽ thay đổi mã của bạn. Bạn có một hàm tạo trong số ViewHolder nơi bạn đang đặt chế độ xem, nhưng như tôi có thể thấy bạn không sử dụng nó trong mã của bạn. Tôi sẽ sử dụng nó hoặc chỉ cần loại bỏ nó. Và một anothet điều, thực sự có một cách tốt hơn để có được những tác dụng tương tự, nhưng nó sẽ chỉ làm việc trên 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

Cảm ơn. Nhưng nó không sử dụng ViewHolder? ("nhưng như tôi có thể thấy bạn không sử dụng nó trong mã của bạn"): viewHolder.txtTitle.setText (album.getTitle (locale)); viewHolder.txtDescription.setText (album.getCopyrightInfo (locale)); – Stan

+0

Chính xác, bạn có thể sử dụng phương thức setTag của chế độ xem để đạt được điều này: http://developer.android.com/reference/android/view/View.html#setTag(int, java.lang.Object), để tham khảo. – hardartcore

+0

Bạn có nghĩa là một dòng mã: convertView.setTag (viewHolder) ;? Tôi không hiển thị dòng này vì không có thay đổi nào so với bản gốc. Sự thay đổi duy nhất trong ListAdapter là tạo ViewHolder và khởi tạo các trường của nó. – Stan

5

tôi sử dụng một cách tiếp cận rất giống như của bạn nhưng tôi mang nó một bước xa hơn, bởi vì ViewHolder là riêng tư đối với lớp bộ điều hợp, tôi kết hợp chặt chẽ nó với lớp bằng cách truyền trong khung nhìn đến hàm tạo của nó và thiết lập các giá trị ở đó

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); 
     } 
    } 

Và trong 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(); 
    } 

Tôi thích làm nó theo cách này vì nó giữ đang adapter của tôi đơn giản hơn trong getView(...) và có lợi ích của các biến thức. Tôi có lẽ sẽ nhận được một tăng tốc độ nhỏ làm cho nó được bảo vệ thay vì nhưng tôi thấy hiệu suất là đủ ngay cả với danh sách lớn.

+3

Nhưng chúng (android .developer guys như Romain Guy) nói rằng ViewHolder phải là lớp tĩnh (một vấn đề về hiệu suất) và cũng là ý tưởng tồi của nó để sử dụng kiểu truy cập riêng nếu lớp ngoài của nó cho adapter (và vì nó has2b tĩnh nó không thể được bên trong cho adapter) nó phải rộng hơn so với private (chúng sử dụng kiểu truy cập mặc định như tôi đã đề cập ở trên). – Stan

+0

Vâng, tôi nhớ đã đọc điều gì đó về điều đó, tôi đã không có một thử nghiệm tốt với hiệu suất. Đó là mẫu xây dựng mà tôi muốn thể hiện, sau đó bạn có được vấn đề đảm bảo không có lớp nào khác có thể truy cập nó khi nó tĩnh. Được bảo vệ tĩnh đủ hạn chế để thực hiện công việc? – ScouseChris

+0

loại quyền truy cập gần nhất đối với riêng tư được bảo vệ để có. Tôi thích cách tiếp cận của bạn và bây giờ thay đổi mã của tôi để sử dụng nó. Không có sự khác biệt thực sự của nó chỉ là về cách mã sẽ như thế nào. Cuz của nó chỉ là về việc gửi 1 tham số thay vì bó các tham số. Tuy nhiên nó liên kết và vi phạm liên kết nhưng ViewHolder giống như một lớp vệ tinh cho adapter nên nó không phải là một việc lớn. – Stan