2011-12-27 31 views
6

Vấn đề của tôi là tôi không biết liệu tôi có nên sử dụng nhiều chế độ xem danh sách hoặc bộ điều hợp mục danh sách tùy chỉnh có thể phát triển động hay không. Ví dụ, đối với một người dùng cụ thể, họ có thể có nhiều hoạt động:
- Chụp ảnh
- Nói gì đi
- Kiểm tra trong
- ...Cách thêm chế độ xem động vào mục ListView khi chạy?

Rõ ràng, danh sách này có thể phát triển như người dùng có thực hiện nhiều hoạt động hơn. Hầu hết thời gian, tôi thường tạo ra một bộ chuyển đổi mục tùy chỉnh mà kéo dài từ BaseAdapter và sử dụng mô hình ItemHolder như sau:

public class PlaceItemAdapter extends BaseAdapter { 
    private Activity  context; 
    private List<Place>  places; 
    private boolean   notifyChanged = false; 

    public PlaceItemAdapter(Activity context, List<Place> places) { 
     super(); 
     this.context = context; 
     this.places = places; 
    } 

    public int getCount() { 
     return places.size(); 
    } 

    public Object getItem(int position) { 
     return places.get(position); 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    public static class ItemViewHolder { 
     TextView nameTextView; 
     TextView typesTextView; 
     TextView ratingTextView; 
     ImageView mapIconImageView; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     ItemViewHolder holder; 
     LayoutInflater inflater = context.getLayoutInflater(); 
     if (convertView == null) { 
      convertView = inflater.inflate(R.layout.place_item, null); 
      holder = new ItemViewHolder(); 
      holder.nameTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_name); 
      holder.typesTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_address); 
      holder.ratingTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_rating); 
      holder.mapIconImageView = (ImageView) convertView.findViewById(R.id.place_item_xml_imageview_location_icon); 

      convertView.setTag(holder); 
     } 
     else { 
      holder = (ItemViewHolder) convertView.getTag(); 
     } 

     holder.nameTextView.setText(places.get(position).getName()); 
     holder.typesTextView.setText(places.get(position).getAddress()); 
     holder.ratingTextView.setText(Integer.toString(places.get(position).getRating())); 
     /* 
     * This task is time consuming! 
     * TODO: find a workaround to handle the image 
     */ 
     // holder.mapIconImageView.setImageBitmap(DownloadImageHelper.downloadImage(places.get(position).getIconUrl())); 
     holder.mapIconImageView.setImageResource(R.drawable.adium); 
     return convertView; 
    } 

    public void notifyDataSetChanged() { 
     super.notifyDataSetChanged(); 
     notifyChanged = true; 
    } 
} 

Sử dụng phương pháp này, số GUI widget là cố định có nghĩa là tôi không thể làm cho listview của tôi mục trông giống như hình dưới đây.

public static class ItemViewHolder { 
     TextView nameTextView; 
     TextView typesTextView; 
     TextView ratingTextView; 
     ImageView mapIconImageView; 
    } 

Cách tiếp cận ban đầu của tôi là tạo chế độ xem động được lồng trong mục bộ điều hợp, tuy nhiên nó sẽ tạo ra chế độ xem trùng lặp. Để tránh chế độ xem trùng lặp, tôi đã đặt convertView thành null có nghĩa là mỗi lần tải, nó sẽ tạo một ItemViewHolder mới và cuối cùng sẽ chiếm hết bộ nhớ của tôi. :(Vậy làm thế nào tôi có thể xử lý tình huống này? Một ví dụ làm việc tối thiểu sẽ được đánh giá rất nhiều.

Duplicate Xem

public class FriendFeedItemAdapter extends BaseAdapter { 
    private List<FriendFeedItem> items; 
    private Activity context; 
    private static LayoutInflater inflater; 
    public ImageLoader imageLoader; 
    private ItemViewHolder viewHolder; 

    public FriendFeedItemAdapter(Activity context, List<FriendFeedItem> items) { 
     this.context = context; 
     this.items = items; 
     inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     imageLoader = new ImageLoader(context.getApplicationContext()); 
    } 

    public int getCount() { 
     return items.size(); 
    } 

    public Object getItem(int position) { 
     return items.get(position); 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    public static class ItemViewHolder { 
     TableLayout table; 
     ImageView imageViewUserPicture; 
     TextView textViewUsername; 
     TextView textViewWhatUserDo; 
     TextView textViewWhere; 
     TextView textViewTime; 
     ImageView imageViewSnapPictureBox; 
     TextView textViewWriteOnWallMessageBox; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
      convertView = inflater.inflate(R.layout.friend_list_feed_item, null); 
      viewHolder = new ItemViewHolder(); 
      viewHolder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table); 
      viewHolder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture); 
      viewHolder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username); 
      viewHolder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do); 
      viewHolder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where); 
      viewHolder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time); 

      convertView.setTag(viewHolder); 
     } 
     else { 
      viewHolder = (ItemViewHolder) convertView.getTag(); 
     } 

     imageLoader.displayImage(items.get(position).getFriendPictureUrl(), viewHolder.imageViewUserPicture); 
     viewHolder.textViewUsername.setText(items.get(position).getFriendName()); 
     viewHolder.textViewWhere.setText("at " + items.get(position).getPlaceName()); 
     viewHolder.textViewTime.setText("@" + items.get(position).getActivityTime()); 

     if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) { 
      viewHolder.textViewWhatUserDo.setText("has checked in."); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) { 
      viewHolder.textViewWhatUserDo.setText("has snap a picture."); 
      // add picture box 
      View rowView = inflater.inflate(R.layout.snap_picture_row_item, null); 
      viewHolder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture); 
      imageLoader.displayImage(items.get(position).getActivitySnapPictureUrl(), viewHolder.imageViewSnapPictureBox); 
      viewHolder.table.addView(rowView); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) { 
      viewHolder.textViewWhatUserDo.setText("has written a message on wall."); 
      // add message box 
      View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null); 
      viewHolder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message); 
      viewHolder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment()); 
      viewHolder.table.addView(rowView); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) { 
      viewHolder.textViewWhatUserDo.setText("has answered a question."); 
     } 
     else { // Challenge.Type.OTHER 
      viewHolder.textViewWhatUserDo.setText("has done some other challenges."); 
     } 

     return convertView; 
    } 
} 

mở rộng bộ nhớ sử dụng

public View getView(int position, View convertView, ViewGroup parent) { 
     ItemViewHolder holder = null; 
     LayoutInflater inflater = context.getLayoutInflater(); 

     convertView = inflater.inflate(R.layout.friend_list_feed_item, null); 
     // create holder 
     holder = new ItemViewHolder(); 
     // default field 
     holder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table); 
     holder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture); 
     holder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username); 
     holder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do); 
     holder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where); 
     holder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time); 
     convertView.setTag(holder); 

     holder.imageViewUserPicture.setImageURI(items.get(position).getFriendPictureUri()); 
     holder.textViewUsername.setText(items.get(position).getFriendName()); 
     holder.textViewWhere.setText("at " + items.get(position).getPlaceName()); 
     holder.textViewTime.setText("@" + items.get(position).getActivityTime()); 

     if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) { 
      holder.textViewWhatUserDo.setText("has checked in."); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) { 
      holder.textViewWhatUserDo.setText("has snap a picture."); 
      // add picture box 
      View rowView = inflater.inflate(R.layout.snap_picture_row_item, null); 
      holder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture); 
      holder.imageViewSnapPictureBox.setImageURI(items.get(position).getActivitySnapPictureUri()); 
      holder.table.addView(rowView); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) { 
      holder.textViewWhatUserDo.setText("has written a message on wall."); 
      // add message box 
      View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null); 
      holder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message); 
      holder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment()); 
      holder.table.addView(rowView); 
     } 
     else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) { 
      holder.textViewWhatUserDo.setText("has answered a question."); 
     } 
     else { // Challenge.Type.OTHER 
      holder.textViewWhatUserDo.setText("has done some other challenges."); 
     } 

     return convertView; 
    } 

enter image description here

enter image description here

Trả lời

9

Nếu bạn có số lượng nhỏ các biến thể có thể (trên ảnh chụp màn hình của bạn tôi có thể thấy 2 mục danh sách khác nhau) Bạn có hai biến thể càng tốt: đếm

  1. Cài đặt các loại khác nhau bằng cách this phương pháp, và cung cấp type cho mọi mục - và bạn có thể sử dụng convertView.

  2. Tạo chế độ xem mục danh sách "đầy đủ" và đặt chế độ hiển thị cho các thành phần mà bạn không muốn thấy trong mục cụ thể.

Một số mã cho # 2:

public class ListTestActivity extends Activity { 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    List<Element> list = new ArrayList<Element>(); 
    list.add(new Element(0)); 
    list.add(new Element(0)); 
    list.add(new Element(1)); 
    list.add(new Element(0)); 
    list.add(new Element(1)); 
    list.add(new Element(1)); 
    list.add(new Element(0)); 
    list.add(new Element(0)); 
    list.add(new Element(1)); 
    list.add(new Element(1)); 
    list.add(new Element(1)); 
    list.add(new Element(0)); 
    list.add(new Element(0)); 
    list.add(new Element(1)); 
    list.add(new Element(0)); 
    list.add(new Element(0)); 
    ((ListView) findViewById(android.R.id.list)).setAdapter(new SampleAdapter(this, list)); 
} 

private class SampleAdapter extends BaseAdapter { 

    private List<Element> list; 
    private Context context; 

    public SampleAdapter(Context context, List<Element> list) { 
     this.list = list; 
     this.context = context; 
    } 

    @Override 
    public int getCount() { 
     return list.size(); 
    } 

    @Override 
    public Element getItem(int position) { 
     return list.get(position); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) 
      switch (getItemViewType(position)) { 
      case 0: 
       convertView = new CheckBox(context); 
       break; 
      default: 
       convertView = new Button(context); 
       break; 
      } 
     // Output here shows that you can lay on getItemViewType(position) as indicator of convertView type or structure 
     Log.e("test", getItemViewType(position) + ": " + convertView.getClass().getSimpleName()); 
     return convertView; 
    } 

    @Override 
    public int getItemViewType(int position) { 
     return getItem(position).type; 
    } 

    @Override 
    public int getViewTypeCount() { 
     return 2; 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 
} 

private class Element { 
    public int type; 

    public Element(int type) { 
     this.type = type; 
    } 
} 
} 
+0

Bạn có thể đưa ra ví dụ làm việc tối thiểu cho phương pháp 1 của mình không? – Chan

+0

xem câu trả lời đã chỉnh sửa của tôi – Jin35

+0

Đó là cách để thực hiện. Tôi thích sử dụng một giao diện 'ItemViewType' cung cấp các phương thức để tạo khung nhìn (trong trường hợp convertView là' null') và dữ liệu ràng buộc cho khung nhìn. Các lớp thực hiện khai báo lớp 'ViewHolder' cụ thể của nó như lớp bên trong. Bạn có thể mở rộng giao diện bằng phương thức accpets để giúp bạn trong 'getItemViewType' – Oderik

2

Bộ điều hợp tùy chỉnh sẽ giải quyết được sự cố của bạn. Điều này là do bạn có thể thay đổi các chế độ xem đang được thêm vào mỗi hàng trong Chế độ xem danh sách, vì bạn có thể thay đổi nội dung thông qua logic mà bạn triển khai trong bộ điều hợp tùy chỉnh.

Khi phương thức getView() trả về một chế độ xem không phải là rỗng, điều này có nghĩa cho hàng cụ thể đó là một chế độ xem đã có sẵn. Vì vậy, nếu trường hợp này xảy ra, bạn có thể hoặc không muốn thay đổi nội dung trong chế độ xem cụ thể đó. Hoặc bạn có thể xây dựng chế độ xem hoàn toàn mới với nội dung động cho hàng cụ thể đó.

Một điều cần lưu ý là getView() sẽ được gọi bao nhiêu lần vì có các mục được tìm thấy trong bộ điều hợp của bạn.

1

Dưới đây là một ý tưởng rằng có thể sẽ cho phép bạn để giới thiệu như nhiều loại item như bạn muốn mà không cần phải sửa đổi bộ chuyển đổi mỗi khi bạn làm:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    AbstractItem abstractItem = ((AbstractItem)getItem(position)); 
    // if null or new item type is different than the one already there 
    if (convertView == null || (convertView.getTag() != null 
      && ((AbstractItem)convertView.getTag()).getType().equals(abstractItem.getType())) { 
      convertView = abstractItem.inflateSelf(getContext()); 
    } 

    abstractItem.fillViewWithData(convertView); 
    convertView.setTag(abstractItem); 
    return convertView; 
} 

public class AbstractItem { 
    public abstract View inflateSelf(Context context); 
    public abstract String getType(); 
    public abstract void fillViewWithData(View view); 
} 

public class PictureSnapItem extends AbstractItem { 
    // data fields 
    WeakReference<Bitmap> wBitmap; 
    String pictureComment; 
    ... 

    public abstract View inflateSelf(Context context) { 
     // get layout inflater, inflate a layout resource, return 
     return ((Activity)context).getLayoutInflater.inflate(R.layout.picture_snap_item); 
    } 
    public abstract String getType() { 
     // return something class-specific, like this 
     return getClass().getCanonicalName(); 
    } 
    public abstract void fillViewWithData(View view) { 
     // fill the view with data from fields, assuming view has been 
     // inflated by this very class's inflateSelf(), maybe throw exception if 
     // required views can't be found 
     ImageView img = (ImageView) view.findViewById(R.id.picture); 
     TextView comment = (TextView) view.findViewById(R.id.picture_comment) 
    } 
} 

... và sau đó mở rộng AbstractItem và thêm trường hợp vào bộ điều hợp, không cần phải thêm bất kỳ điều gì nếu mệnh đề vào getView() nữa.

Các vấn đề liên quan