2013-03-07 14 views
10

Mam ListView, który jest złożony, ponieważ istnieją możliwe scenariusze dla 4 typów widoków, np. { book, movie, music cd, concert }Złożony przykład ListView getItemViewType()

Obecnie, aby zdecydować, jaki przedmiot napompować itp., Otrzymuję pozycję, która odnosi się do wiersza listy. Zrobię wtedy switch() w polu typu obiektu.

Zostało mi wiele kodu i ciężkiego podnoszenia w getView().

Czy mam rację, mówiąc, że getItemViewType() służy do zwracania prawidłowego typu widoku dla bieżącego elementu?

Gdzie znajdę przykład ListAdapter, który wykorzystuje to podejście? Uwaga: to jest próba wygładzenia mojej ListView, która jest teraz dość powolna.

Dzięki

EDIT: My Adapter

public class MyListAdapter extends BaseAdapter implements ListAdapter { 

    private Context ctx; 
    private int layoutResourceId; 
    private ArrayList<ItemType> items; 

    public MyListAdapter(Context context, ArrayList<ItemType> data) { 

     this.layoutResourceId = R.layout.timeline_item_row; 
     this.ctx = context; 
     this.setitems(data); 
    } 

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

     View row = convertView; 
     TimelineHolder holder = null; 
     ItemType transaction = getitems().get(position); 

     if (row == null) { 

      LayoutInflater inflater = ((Activity) ctx).getLayoutInflater(); 
      row = inflater.inflate(layoutResourceId, parent, false); 

      holder = new TimelineHolder(); 
      holder.imgActivityIcon = (ImageView)row.findViewById(R.id.imgActivityImageIcon); 
      holder.imgActivityLabel = (ImageView)row.findViewById(R.id.imgActivityImageLabel); 
      holder.lblMerchantName = (TextView)row.findViewById(R.id.lblMerchantName); 
      holder.lblLocation = (TextView)row.findViewById(R.id.lblLocation); 
      holder.lblActivityType = (TextView)row.findViewById(R.id.lblActivityType); 
      holder.lblActivityLabelUpper = (TextView)row.findViewById(R.id.lblActivityTypeLabel); 
      holder.lblTimeSinceActivity = (TextView)row.findViewById(R.id.lblTimeSinceActivity); 
      holder.lblActivityAmount = (TextView)row.findViewById(R.id.lblActivityAmount); 

      row.setTag(holder); 

     } 
     else { 

      holder = (TimelineHolder) row.getTag(); 
     } 

     // Get/Populate common values here 

     String address = ""; 

     Date hostTime = Helper.parse8601UTC(transaction.getCurrentHostTime()); 
     Date transactionTime = Helper.parse8601UTC(transaction.getHostTransactionTime()); 
     String merchantName = transaction.getMerchant().getName(); 

     holder.lblMerchantName.setText(merchantName); 
     holder.lblLocation.setText(address); 
     holder.lblTimeSinceActivity.setText(Helper.timeSince(transactionTime, hostTime)); 
     holder.lblActivityAmount.setText(Helper.doubleToCurrency(transaction.getAmount(), transaction.getCurrency())); 

     switch (transaction.getTransactionTypeId()) { 

     case TYPE_ONE: 

      holder.imgActivityIcon.setImageResource(R.drawable.redemmedicon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Loyalty_Earned); 
      holder.lblActivityLabelUpper.setText(R.string.EARNED); 
      holder.lblActivityAmount.setText(transaction.getResponsePoints() + " pts"); 

      break; 

     case TYPE_TWO: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Prepay_Redeem_Refund); 
      holder.lblActivityLabelUpper.setText(R.string.REDEEMED); 

      break; 

     case TYPE_THREE: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityLabelUpper.setText(R.string.REFUND); 
      holder.lblActivityType.setText(R.string.Prepay_Purchase_Refund); 

      break; 
     case TYPE_FOUR: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityLabelUpper.setText(R.string.REFUND); 
      holder.lblActivityType.setText(R.string.Prepay_Deposit_Refund); 

      break; 

     case TYPE_FIVE: 

      holder.imgActivityIcon.setImageResource(R.drawable.reward_earned_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Reward_Redeemed); 
      holder.lblActivityLabelUpper.setText(R.string.REDEEMED); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_SIX: 

      holder.imgActivityIcon 
        .setImageResource(R.drawable.reward_earned_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag); 
      holder.lblActivityType.setText(R.string.Points_Redeemed); 
      holder.lblActivityLabelUpper.setText(R.string.REDEEMED); 
      holder.lblActivityAmount.setText(transaction.getResponsePoints() 
        + " pts"); 

      break; 

     case TYPE_SEVEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.stamp_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag); 
      holder.lblActivityType.setText(R.string.Checked_In); 
      holder.lblActivityLabelUpper.setText(R.string.CHECK_IN); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_EIGHT: 

      holder.imgActivityIcon.setImageResource(R.drawable.shared_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag); 
      holder.lblActivityType.setText(R.string.Shared_Coupon); 
      holder.lblActivityLabelUpper.setText(R.string.SHARED); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_NINE: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Prepay_Deposit); 
      holder.lblActivityLabelUpper.setText(R.string.DEPOSIT); 

      break; 

     case TYPE_TEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.redeemed_flag); 
      holder.lblActivityType.setText(R.string.Prepay_Purchase); 
      holder.lblActivityLabelUpper.setText(R.string.PURCHASE); 

      break; 

     case TYPE_ELEVEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Prepay_Redeemed); 
      holder.lblActivityLabelUpper.setText(R.string.REDEEMED); 

      break; 

     case TYPE_TWELVE: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Refund); 
      holder.lblActivityLabelUpper.setText(R.string.REFUND); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_THIRTEEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.prepay_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.reversal); 
      holder.lblActivityLabelUpper.setText(R.string.REVERSAL); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_FOURTEEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.unlocked_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Check_In_Reward_Unlocked); 
      holder.lblActivityLabelUpper.setText(R.string.UNLOCKED); 
      holder.lblActivityAmount.setText(""); 

      break; 

     case TYPE_FIFTEEN: 

      holder.imgActivityIcon.setImageResource(R.drawable.reward_earned_icon_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(R.string.Coupon_Received); 
      holder.lblActivityLabelUpper.setText(R.string.RECEIVED); 
      holder.lblActivityAmount.setText(""); 

      break; 

     default: 

      holder.imgActivityIcon.setImageResource(R.drawable.stamp_2x); 
      holder.imgActivityLabel.setImageResource(R.drawable.earned_flag); 
      holder.lblActivityType.setText(""); 
      holder.lblActivityLabelUpper.setText(""); 
      holder.lblActivityAmount.setText(""); 

      break; 
     } 

     return row; 
    } 

    @Override 
    public int getCount() { 

     return getitems() == null ? 0 : getitems().size(); 
    } 

    @Override 
    public Object getItem(int position) { 

     return getitems() == null ? null : getitems().get(
       position); 
    } 

    @Override 
    public long getItemId(int position) { 

     return layoutResourceId; 
    } 

    public void addItem(ItemType item, boolean addFirst) { 

     if (addFirst) { 

      getitems().add(0, item); 
     } else { 

      getitems().add(item); 
     } 

     notifyDataSetChanged(); 
    } 

    public ArrayList<ItemType> getitems() { 
     return items; 
    } 

    public void setitems(ArrayList<ItemType> items) { 
     this.items = items; 
    } 

    public int getFirstTransactionId() { 

     int result = 0; 

     if (items != null && !items.isEmpty()) { 

      ItemType txn = items.get(0); 
      result = txn.getId(); 
     } 

     return result; 
    } 

    public int getLastTransactionId() { 

     int result = 0; 

     if (items != null && !items.isEmpty()) { 

      ItemType txn = items.get(items.size() - 1); 
      result = txn.getId(); 
     } 

     return result; 
    } 

    @Override 
    public int getViewTypeCount() { 

     return 1; 
    } 

    @Override 
    public int getItemViewType(int position) { 

     return 0; 
    } 
} 

Odpowiedz

8

*** Zaktualizowane podpowiedzi ****
Nie realizują getViewTypeCount() i getItemViewType() poprawnie.

Przeczytaj samouczek, który dostarczyłem w odnośnikach poniżej. Nie chcę ich ponownie tłumaczyć, bo zrobię to gorzej. Najpierw przeczytaj poniżej, ponieważ tak naprawdę nie potrzebujesz tego, ponieważ masz tylko jeden typ widoku.


Wariant 1: Tworzenie 16-różne wiersze z prawidłowym obrazem zasobów. Następnie wywołaj metodę getItemViewType (pozycja) w metodzie getView(). Wykonaj przełączenie i nadmuchaj odpowiedni wiersz w zależności od typu widoku, który powraca. (Tutorial wyjaśni to). W ten sposób nie musisz ciągle wywoływać wywołania "setImageResource", co jest kosztowne.

Opcja 2: Na podstawie uchwytu widzenia wydaje się, że masz tylko 1 Widok i jesteś po prostu zmieniając 3 pól tekstowych i 2 bitmap. Ale każde wywołanie bitmapy jest ciężkie, musisz utworzyć HashMap, aby buforować te ikony. Przy każdym wywołaniu odwołaj się do mapy skrótu, jeśli element nie istnieje, utwórz go, dodaj i kontynuuj. Jest to ważne, ponieważ każde wywołanie metody setImageResource() wykonuje dekodowanie bitmapowe i wymaga czasu. To tutaj popełniamy prawdziwy błąd: Zobacz pseudo kod poniżej.

private static HashMap<Integer, Bitmap> cache; 
static class BitmapCache { 
    public static Bitmap get(Integer id) { 
     if (cache.containsKey(id)) { 
      return cache.get(id); 
     } else { 
      Bitmap t = BitmapFactory.decodeResource(getContext(), id); 
      cache.put(key, t); 
      return t; 
     } 
    } 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder item = null; 
    Object o = getItem(position); 

    View mRow = convertView; 
    if (mRow == null) { 
     LayoutInflater li = LayoutInflater.from(getContext()); 
     switch (getItemViewType(position)) { 
     case VIEW_ONLINE: 
      mRow = li.inflate(R.layout.row_online, parent, false); 
      break; 
     default: 
      // default to sortable 
      mRow = li.inflate(R.layout.row_offline, parent, false); 
      break; 
     } 

     item = new ViewHolder(mRow); 
     mRow.setTag(item); 
    } else { 
     item = (ViewHolder) mRow.getTag(); 
    } 


    item.icon.setImageBitmap(BitmapCache.get(object.key)); 

    return mRow; 
} 

* Stary odpowiedź z samouczków *
Istnieje kilka stanowisk na StackOverflow już, że po prostu przeszły wczoraj związane z tym. (Zobacz linki poniżej).

  1. Tak, użyj funkcji getItemViewType(), aby pobrać poprawny typ widoku. Jak rozumiem, prawdziwą korzyścią jest tutaj optymalizacja widoku podczas wywołania getView(). Implementacja metody getItemViewType() pozwala typowi getView() zwrócić poprawny buforowany widok.
  2. Użyj wzorca uchwytu widoku statycznego do wyświetlania tekstu i obrazów w zawyżonym widoku. Nie powinieneś zawyżać widoku za każdym razem, powinieneś ponownie używać convertView dostarczonego przez wywołanie getView().
  3. Koniecznie wdrożyć getViewTypeCount()

Oto poradnik, który wyjaśnia, w jaki sposób wykonać głębokości niestandardowej listy widoki tym optymalizacje. http://www.vogella.com/articles/AndroidListView/article.html

Oto dwa StackOverflow postów, które również omawiać to, co staramy się robić:
1. Android Programming tutorials - Tutorial 5
2. Restaurant Program Tutorial

+0

Dzięki, może muszę szukać ciężej. Obecnie używam wzorca przeglądarki, ale wygląda na to, że w większości przypadków widok ConvertView ma wartość zerową lub identyfikator jest nieprawidłowy. – conor

+0

Jeśli te samouczki nie pomagają - umieść niestandardową kartę i mogę na nią spojrzeć. W widoku listy miałem 2 widoki tekstowe i 2 widoki obrazów na wiersz z łącznie 4 różnymi typami wierszy. Czy korzystasz z wielu bitmap w swoim widoku? – Cookster

+0

Właśnie dodałem kod adaptera. Używam kilku obrazów w porządku, tła i dwóch innych. Właściwie to właśnie teraz patrzę na obrazy. reddemed/earned ma ~ 4kb każda, a tło to 500b. To około 4,5kb obrazów w jednym wierszu. Czy to za dużo? – conor