2009-11-02 20 views
10

SDK demo örneklerinden EfficientAdapter example temel alınarak BaseAdapter'ın genişletilmiş bir sürümünü kullanıyorum.Android: İki farklı Görünümlü EfficientAdapter

Verilerim, temel olarak listPlaces.getValues() aracılığıyla erişilebilen gerçek yerler listesine sahip bir ArrayList tutan bir nesnedir (ListPlaces). Bu ArrayList verileri aralıklara göre sıralanır ve ArrayList, veri içermeyen bazı özel öğelerden (ayırıcılar) oluşur, ancak bayrağı true olarak ayarlanır. Benim EfficientAdapter o public boolean isEnabled(int position) için false döner ve public View getView(int position, View convertView, ViewGroup parent) geçerli veri nesnesi gerçek veriler oluşur ya da sadece bir ayırıcı kukla ise bağlı olarak iki farklı düzenler şişirir bir ayırıcı bir veri nesnesi alır Şimdi her

.

Bu, düzeni her seferinde şişirirsem harika çalışır. Ancak, düzeni her seferinde şişirmek ve findViewById'u çağırmak, ListView'u neredeyse istenmeyen şekilde yavaşlatır.

Bu yüzden EfficientAdapter'i ViewHolder yaklaşımıyla kullanmayı denedim. Ama bu kutudan çıkmadı, erişmeye çalıştığım iki farklı görüşten dolayı. Bu yüzden, convertView != null (diğer durum), ViewHolder aracılığıyla bizim düzenimizdeki öğelere eriştiğinde ve önceki Görünüm bir ayırıcı olduğunda, tabiki sadece "gerçek" öğeler düzeninde kullanılabilen bir TextView'e erişmek için çalışmaz . Bir önceki listRow şu ankinden farklı olduğu zaman

yüzden de aynı zamanda benim getView() düzen sadece convertView == null şişirmek için zorlamak, ancak: if (convertView == null || (listRow != listRow_previous)) { [....] }

Bu neredeyse artık çalışıyor gibi görünüyor. Ya da en azından en baştan çökmez. Ama hala çöküyor ve farklı ne yapacağımı bilmiyorum. convertView.getID() ve convertView.getResources()'a bakmayı denedim, ancak bu şimdiye kadar çok yardımcı olmadı. Belki de bir başkasının, mevcut convertView numaranın liste öğesi düzeniyle mi yoksa liste ayırıcı düzeniyle mi eşleştiğini nasıl kontrol edebileceğime dair bir fikri vardır. Teşekkürler.

İşte kod. Hiç bir [...] Almam gereken daha az önemli kodunu orada çıkardı durumlarda Kolay okunması ve anlaşılması: Burada

private class EfficientAdapter extends BaseAdapter { 
    private LayoutInflater mInflater; 
    private ListPlaces listPlaces; 

    private ListRow listRow; 
    private ListRow listRow_previous; 


    public EfficientAdapter(Context context, ListPlaces listPlaces) { 
     // Cache the LayoutInflate to avoid asking for a new one each time. 
     mInflater = LayoutInflater.from(context); 

     // Data 
     this.listPlaces = listPlaces; 
    } 

    /** 
    * The number of items in the list is determined by the number of items 
    * in our ArrayList 
    * 
    * @see android.widget.ListAdapter#getCount() 
    */ 
    public int getCount() { 
     return listPlaces.getValues().size(); 
    } 

    /** 
    * Since the data comes from an array, just returning the index is 
    * sufficent to get at the data. If we were using a more complex data 
    * structure, we would return whatever object represents one row in the 
    * list. 
    * 
    * @see android.widget.ListAdapter#getItem(int) 
    */ 
    public Object getItem(int position) { 
     return position; 
    } 

    /** 
    * Use the array index as a unique id. 
    * 
    * @see android.widget.ListAdapter#getItemId(int) 
    */ 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public boolean isEnabled(int position) { 
     // return false if item is a separator: 
     if(listPlaces.getValues().get(position).separator >= 0) 
      return false; 
     else 
      return true; 
    } 

    @Override 
    public boolean areAllItemsEnabled() { 
     return false;   
    } 



    /** 
    * Make a view to hold each row. 
    * 
    * @see android.widget.ListAdapter#getView(int, android.view.View, 
    *  android.view.ViewGroup) 
    */ 
    public View getView(int position, View convertView, ViewGroup parent) { 

     // Get the values for the current list element 
     ListPlacesValues curValues = listPlaces.getValues().get(position); 
     if (curValues.separator >= 0) 
      listRow = ListRow.SEPARATOR; 
     else 
      listRow = ListRow.ITEM; 
     Log.i(TAG,"Adapter: getView("+position+") " + listRow + " (" + listRow_previous + ") -> START"); 

     // A ViewHolder keeps references to children views to avoid unneccessary calls 
     // to findViewById() on each row. 
     ViewHolder holder; 

     // When convertView is not null, we can reuse it directly, there is no need 
     // to reinflate it. We only inflate a new View when the convertView supplied 
     // by ListView is null. 
     if (convertView == null || (listRow != listRow_previous)) { 
      Log.i(TAG, "--> (convertView == null) at position: " + position); 
      // Creates a ViewHolder and store references to the two children views 
      // we want to bind data to. 
      holder = new ViewHolder(); 

      if (listRow == ListRow.SEPARATOR) { 
       convertView = mInflater.inflate(R.layout.taxonomy_list_separator, null); 
       holder.separatorText = (TextView) convertView.findViewById(R.id.separatorText); 
       convertView.setTag(holder); 
       Log.i(TAG,"\tCREATE SEPARATOR: convertView ID: " + convertView.getId() + " Resource: " + convertView.getResources()); 

      } 
      else { 

       convertView = mInflater.inflate(R.layout.taxonomy_listitem, null); 
       holder.name = (TextView) convertView.findViewById(R.id.name); 
       holder.category = (TextView) convertView.findViewById(R.id.category); 
       // [...] 

       convertView.setTag(holder); 

       Log.i(TAG,"\tCREATE ITEM: convertView ID: " + convertView.getId() + " Resource: " + convertView.getResources()); 
      } 
     } else { 
      // Get the ViewHolder back to get fast access to the TextView 
      // and the ImageView. 
      Log.i(TAG,"\tconvertView ID: " + convertView.getId() + " Resource: " + convertView.getResources()); 

      holder = (ViewHolder) convertView.getTag(); 
      convertView.setAnimation(null); 
     } 

     /* Bind the data efficiently with the holder */ 
     if (listRow == ListRow.SEPARATOR) { 
      String separatorText; 
      switch (curValues.separator) { 
      case 0: separatorText="case 0"; break; 
      case 1: separatorText="case 1"; break; 
      case 2: separatorText="case 2"; break; 
      // [...] 
     default: separatorText="[ERROR]"; break; 
      } 
      holder.separatorText.setText(separatorText); 
     } 
     else { 
      // Set the name: 
      holder.name.setText(curValues.name); 
      // Set category 
      String cat = curValues.classification.toString(); 
      cat = cat.substring(1,cat.length()-1); // removing "[" and "]" 
      if (cat.length() > 35) { 
       cat = cat.substring(0, 35); 
       cat = cat + "..."; 
      } 
      holder.category.setText(cat); 

      // [...] (and many more TextViews and ImageViews to be set) 

     } 

     listRow_previous = listRow; 
     Log.i(TAG,"Adapter: getView("+position+") -> DONE"); 
     return convertView; 
    } 

    private class ViewHolder { 
     TextView name; 
     TextView category; 
     // [...] -> many more TextViews and ImageViews 

     TextView separatorText; 
    } 
} 

Ve benim Logcat çıkışı:

755  ListPlaces_Activity I onPostExecute: notifyDataSetChanged()                         
    755  ListPlaces_Activity I Adapter: getView(0) SEPARATOR (null) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 0                        
    755  ListPlaces_Activity I  CREATE SEPARATOR: convertView ID: 2131296317 Resource: [email protected]         
    755  ListPlaces_Activity I Adapter: getView(0) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(1) ITEM (SEPARATOR) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 1                        
    755  ListPlaces_Activity I  CREATE ITEM: convertView ID: 2131296317 Resource: [email protected]          
    755  ListPlaces_Activity I Adapter: getView(1) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(2) SEPARATOR (ITEM) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 2                        
    755  ListPlaces_Activity I  CREATE SEPARATOR: convertView ID: 2131296317 Resource: [email protected]         
    755  ListPlaces_Activity I Adapter: getView(2) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(3) ITEM (SEPARATOR) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 3                        
    755  ListPlaces_Activity I  CREATE ITEM: convertView ID: 2131296317 Resource: [email protected]          
    755  ListPlaces_Activity I Adapter: getView(3) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(4) ITEM (ITEM) -> START                        
    755  ListPlaces_Activity I  convertView ID: 2131296317 Resource: [email protected]              
    755  ListPlaces_Activity I Adapter: getView(4) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(5) ITEM (ITEM) -> START                        
    755  ListPlaces_Activity I  convertView ID: 2131296317 Resource: [email protected]              
    755  ListPlaces_Activity I Adapter: getView(5) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(6) ITEM (ITEM) -> START                        
    755  ListPlaces_Activity I  convertView ID: 2131296317 Resource: [email protected]              
    755  ListPlaces_Activity I Adapter: getView(6) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(0) SEPARATOR (ITEM) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 0                        
    755  ListPlaces_Activity I  CREATE SEPARATOR: convertView ID: 2131296317 Resource: [email protected]         
    755  ListPlaces_Activity I Adapter: getView(0) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(1) ITEM (SEPARATOR) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 1                        
    755  ListPlaces_Activity I  CREATE ITEM: convertView ID: 2131296317 Resource: [email protected]          
    755  ListPlaces_Activity I Adapter: getView(1) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(2) SEPARATOR (ITEM) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 2                        
    755  ListPlaces_Activity I  CREATE SEPARATOR: convertView ID: 2131296317 Resource: [email protected]         
    755  ListPlaces_Activity I Adapter: getView(2) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(3) ITEM (SEPARATOR) -> START                       
    755  ListPlaces_Activity I --> (convertView == null) at position: 3                        
    755  ListPlaces_Activity I  CREATE ITEM: convertView ID: 2131296317 Resource: [email protected]          
    755  ListPlaces_Activity I Adapter: getView(3) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(4) ITEM (ITEM) -> START                        
    755  ListPlaces_Activity I  convertView ID: 2131296317 Resource: [email protected]              
    755  ListPlaces_Activity I Adapter: getView(4) -> DONE                           
    755  ListPlaces_Activity I Adapter: getView(5) ITEM (ITEM) -> START                        
    755  ListPlaces_Activity I  convertView ID: 2131296317 Resource: [email protected]              
    755   AndroidRuntime D Shutting down VM                              
    755    dalvikvm W threadid=3: thread exiting with uncaught exception (group=0x4001aa28)                 
    755   AndroidRuntime E Uncaught handler: thread main exiting due to uncaught exception                  
    755   AndroidRuntime E java.lang.NullPointerException                          
    755   AndroidRuntime E  at com.tato.main.ListPlaces_Activity$EfficientAdapter.getView(ListPlaces_Activity.java:330)          
    755   AndroidRuntime E  at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:191)             
    755   AndroidRuntime E  at android.widget.AbsListView.obtainView(AbsListView.java:1255)                 
    755   AndroidRuntime E  at android.widget.ListView.makeAndAddView(ListView.java:1658)                 
    755   AndroidRuntime E  at android.widget.ListView.fillDown(ListView.java:637)                   
    755   AndroidRuntime E  at android.widget.ListView.fillFromTop(ListView.java:694)                  
    755   AndroidRuntime E  at android.widget.ListView.layoutChildren(ListView.java:1502)                 
    755   AndroidRuntime E  at android.widget.AbsListView.onLayout(AbsListView.java:1112)                 
    755   AndroidRuntime E  at android.view.View.layout(View.java:6569)                      
    755   AndroidRuntime E  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)               
    755   AndroidRuntime E  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)               
    755   AndroidRuntime E  at android.widget.LinearLayout.onLayout(LinearLayout.java:918)                 
    755   AndroidRuntime E  at android.view.View.layout(View.java:6569)                      
    755   AndroidRuntime E  at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                 
    755   AndroidRuntime E  at android.view.View.layout(View.java:6569)                      
    755   AndroidRuntime E  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)               
    755   AndroidRuntime E  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)               
    755   AndroidRuntime E  at android.widget.LinearLayout.onLayout(LinearLayout.java:918)                 
    755   AndroidRuntime E  at android.view.View.layout(View.java:6569)                      
    755   AndroidRuntime E  at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                 
    755   AndroidRuntime E  at android.view.View.layout(View.java:6569)                      
    755   AndroidRuntime E  at android.view.ViewRoot.performTraversals(ViewRoot.java:979)                 
    755   AndroidRuntime E  at android.view.ViewRoot.handleMessage(ViewRoot.java:1613)                  
    755   AndroidRuntime E  at android.os.Handler.dispatchMessage(Handler.java:99)                   
    755   AndroidRuntime E  at android.os.Looper.loop(Looper.java:123)                      
    755   AndroidRuntime E  at android.app.ActivityThread.main(ActivityThread.java:4203)                 
    755   AndroidRuntime E  at java.lang.reflect.Method.invokeNative(Native Method)                   
    755   AndroidRuntime E  at java.lang.reflect.Method.invoke(Method.java:521)                    
    755   AndroidRuntime E  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)            
    755   AndroidRuntime E  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)                 
    755   AndroidRuntime E  at dalvik.system.NativeStart.main(Native Method)  
+0

Satır 300'ün stacktrace'de nerede olduğunu gösteren bir yorum ekleyebilir misiniz? Eğer ise (curValues.separator> = 0) 'ise, listenin sonuna kadar 1'e kadar olan pozisyonları idare edebilecek misiniz? – rsp

cevap

12

Unuttun geçersiz kılmanız gereken birkaç yöntem: getViewTypeCount() ve getItemViewType(). Tüm satırların aynı olduğu listeler için bunlar gerekli değildir, ancak senaryonuz için çok önemlidir. Bunları doğru bir şekilde uygulayın ve Android, başlıklar ve ayrıntı satırları için ayrı nesne havuzlarını koruyacaktır.

Veya, bakabilir:

+1

Hızlı yanıtınız için teşekkürler. GetViewTypeCount() ve getItemViewType() ile ipucu çok kullanışlıdır. Bu bağdaştırıcıyı seviyorum. Ayrıca ve Jeff Sharkey'in kaynak kodunu paylaştığınız için teşekkür ederiz. Zaten geçen hafta baktım, ama şu anda kapalı bir kaynak projesinde çalışıyorum, en azından GPL örneklerini uygulayamıyorum. Bu yüzden nihayet yardımlarınız sayesinde nihayet işe yarayan kendi uygulamamı başlatmaya karar verdim. Muchas gracias! – znq

+0

güncellendi yorumlama bağlantısı çalışmıyor. hala çalışan bağlantı bulamadı – rtack

6

getViewTypeCount() ve getItemViewType() ile ipucu sayesinde şimdi mükemmel çalışıyor.

çok basit olan bu iki yöntem edildi Uygulanması: Onun cevabını da listRow_previous için işaretini kaldırın anlamına gelir farklı liste öğeleri için farklı nesne havuzları koruyacak bu şekilde Android belirtilen

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

@Override 
public int getItemViewType(int position) { 
if(listPlaces.getValues().get(position).separator >= 0) 
    return 0; 
else 
    return 1; 
} 

commonsware gibi örneğimde ve if (convertView == null || (listRow != listRow_previous))'u yalnızca if (convertView == null) olarak değiştirin.

İlgili konular