2013-04-09 7 views
9

Mam niejasne problemy dotyczące recyklingu widoków w metodzie getView niestandardowego adaptera tablicowego.Recykling widoków w niestandardowym adapterze tablicowym: jak dokładnie jest obsługiwany?

Rozumiem, że elementy są ponownie używane, ale skąd mam wiedzieć, co należy zaimplementować w pierwszej części instrukcji if, a co w drugim?

Teraz mam następujący kod. Doszedłem do tego pytania z powodu upuszczenia kodu w drugiej części instrukcji, co skutkuje listą pierwszych 9 elementów, które powtarzają się wielokrotnie, zamiast wszystkich elementów. Nie wiedziałem dokładnie, co powoduje to dokładnie ...

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

     if (row == null) { 
      LayoutInflater inflater = ((Activity) context).getLayoutInflater(); 
      row = inflater.inflate(layoutResourceId, parent, false); 

      title = getItem(position).getTitle(); 
      size = calculateFileSize(position); 

      txtTitle = (TextView) row.findViewById(R.id.txtTitle); 
      tvFileSize = (TextView) row.findViewById(R.id.tvFileSize); 

      txtTitle.setText(title); 
      tvFileSize.setText(size); 

     } else { 

      title = getItem(position).getTitle(); 
      size = calculateFileSize(position); 

      txtTitle = (TextView) row.findViewById(R.id.txtTitle); 
      tvFileSize = (TextView) row.findViewById(R.id.tvFileSize); 

      txtTitle.setText(title); 
      tvFileSize.setText(size); 
     } 

     return row; 
    } 
+0

Dziękuję wszystkim za szybką i dobre wyjaśnienie ! Mam trochę czytania/oglądania do zrobienia :) Naprawdę to doceniam! –

+0

możliwy duplikat [dlaczego działa ViewHolder pattren?] (Http://stackoverflow.com/questions/5973917/why-does-the-viewholder-pattren-work) –

Odpowiedz

13

Rozumiem, że elementy są ponownie wykorzystywane, ale skąd mam wiedzieć, dokładny co do wdrożenia w pierwszej części if, a co w drugim?

Organizacja jest bardzo proste, gdy pojawi się zawiesić go:

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

    if (convertView == null) { 
     /* This is where you initialize new rows, by: 
     * - Inflating the layout, 
     * - Instantiating the ViewHolder, 
     * - And defining any characteristics that are consistent for every row */ 
    } else { 
     /* Fetch data already in the row layout, 
     * primarily you only use this to get a copy of the ViewHolder */ 
    } 

    /* Set the data that changes in each row, like `title` and `size` 
    * This is where you give rows there unique values. */ 

    return convertView; 
} 

o szczegółowe wyjaśnienia, w jaki sposób ListView za RecycleBin działa i dlaczego ViewHolders są ważne zegarek Turbo Charge your UI, Google I/O przedstawienie przez Android prowadzą programistów ListView.

+0

Świetny link, Sam! Już miałem to opublikować, dopóki nie zobaczyłem, że to zrobiłeś. Najpierw dowiedziałem się o tym od ciebie i było to niezwykle pomocne. Dzięki! – codeMagic

+0

Dzięki, to jest dla mnie. Możesz również opublikować tę wiadomość, a nawet kolejną prezentację "World of ListView". Z prezentacji I/O można się wiele nauczyć. – Sam

+0

Zwykle umieszczam ten link na takich pytaniach, ale zawsze daję ci kredyt za to, że wiem. Chciałbym zobaczyć innych, ale jeszcze nie znalazłem żadnych innych. Szukam tego. – codeMagic

15

To proste. Po raz pierwszy żaden rząd nie jest tworzony, więc musisz je nadmuchać. Następnie system operacyjny Android może zdecydować o recyklingu widoków, które już zostały zawyżone i które nie są już widoczne. Te są już zawyżone i przekazane do parametru convertView, więc wszystko, co musisz zrobić, to ułożyć go tak, aby pokazywał nowy bieżący element, na przykład umieszczając odpowiednie wartości w różnych polach tekstowych.

enter image description here

W skrócie, w pierwszej części należy wykonać inflację i wypełnić wartości, w drugim if (if convertView != null) należy tylko nadpisać boiska ponieważ ze względu na widok zostało poddane recyklingowi, że TextView zawierają wartości starego przedmiotu.

This post i this są dobrym punktem wyjścia

+0

+1 dla diagramu –

4

Zalecam użycie uchwytu widoku i wzorca konwersji, aby utworzyć listę, ponieważ będzie bardziej wydajna. Here to dobre wytłumaczenie tego, jak działa ze strategią ponownego wykorzystania. To odpowie na twoje pytanie, jak działa re-cycling. Jeśli chcesz odwołać się do próbki kodu, mam ją na GitHub.

Mam nadzieję, że to pomoże.

1

Ostatnia część pytania, którego naprawdę nie mogłem pojąć bez zdjęcia efektu, ale dla pierwszej części "co zaimplementować w pierwszej części instrukcji if, a co w drugim" Myślę, że ja " ve uznają tę implementację za bardzo powszechną.

Najpierw znajdziesz odniesienia do widoku i zapiszesz je w statycznej klasie ViewHolder, którą następnie dołączasz do znacznika nowego nadpisanego widoku. Ponieważ widok listy przetwarza widoki, a convertView jest przekazywany getView, otrzymuje się ViewHolder ze znacznika convertView, dzięki czemu nie trzeba ponownie szukać odnośników (co znacznie poprawia wydajność) i aktualizować dane widoku z danymi obiektu na podana pozycja.

Z technicznego punktu widzenia nie obchodzi Cię, jaką pozycję widział widok, ponieważ wszystko, na czym Ci zależy, to odniesienia do widoków, które musisz zaktualizować, które są przechowywane w jego ViewHolder.

@Override 
public View getView(int position, View convertView, ViewGroup container) { 
    ViewHolder holder; 
    Store store = getItem(position); 
    if (convertView == null) { 
     convertView = mLayoutInflater.inflate(R.layout.item_store, null); 

     // create a holder to store references 
     holder = new ViewHolder(); 

     // find references and store in holder 
     ViewGroup logoPhoneLayout = (ViewGroup) convertView 
       .findViewById(R.id.logophonelayout); 
     ViewGroup addressLayout = (ViewGroup) convertView 
       .findViewById(R.id.addresslayout); 

     holder.image = (ImageView) logoPhoneLayout 
       .findViewById(R.id.image1); 
     holder.phone = (TextView) logoPhoneLayout 
       .findViewById(R.id.textview1); 
     holder.address = (TextView) addressLayout 
       .findViewById(R.id.textview1); 

     // store holder in views tag 
     convertView.setTag(holder); 
    } else { 

     // Retrieve holder from view 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    // fill in view with our store (at this position) 
    holder.phone.setText(store.phone); 
    holder.address.setText(store.getFullAddress()); 

    UrlImageViewHelper.setUrlDrawable(holder.image, store.storeLogoURL, 
      R.drawable.no_image); 

    return convertView; 
} 

private static class ViewHolder { 
    ImageView image; 
    TextView phone; 
    TextView address; 
} 
5

Chcesz utworzyć klasę ViewHolder w MainActivity. Coś jak

static class ViewHolder 
    { 
     TextView tv1; 
     TextView tv2; 
    } 

Następnie w getView, po raz pierwszy można dostać swój Views z XML w if i ponownie je potem w else

View rowView = convertView; 
     if (rowView == null) 
     { 
      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      rowView = inflater.inflate(R.layout.layout_name_to_inflate, parent, false); 
      holder = new ViewHolder(); 
      holder.tv1= (TextView) rowView.findViewById(R.id.textView1); 
      holder.tv2 = (RadioGroup) rowView.findViewById(R.id.textView2);    
      rowView.setTag(holder); 
     } 
     else 
     { 
      holder = (ViewHolder) rowView.getTag(); 
     }