Frage

Ich verwende eine erweiterte Version von BaseAdapter basierend auf dem EfficientAdapter Beispiel aus den SDK Demo Proben.

Meine Daten sind im Grunde ein Objekt (ListPlaces), die eine ArrayList mit der aktuellen Liste der Orte, erreichbar über listPlaces.getValues() hält. Diese Arraydaten durch Bereich sortiert und die ArrayList bestehen aus einigen speziellen Artikel (Separatoren), ohne Daten, sondern ein separator Flag auf true.

Nun, wenn mein EfficientAdapter bekommt ein Datenobjekt, das ein Separator es false für public boolean isEnabled(int position) gibt und public View getView(int position, View convertView, ViewGroup parent) aufbläst zwei verschiedene Layouts je nachdem, ob das aktuelle Datenobjekt bestand aus realen Daten oder nur ein Separator Blind.

Dies funktioniert gut, wenn ich das Layout jedes Mal aufzublasen. Allerdings Aufblasen des Layout jedes Mal und ruft findViewById macht die ListView fast unusabely langsam.

So habe ich versucht, die EfficientAdapter mit ViewHolder Ansatz zu verwenden. Aber das hat nicht funktioniert direkt aus der Box, weil der zwei verschiedenen Ansichten, die ich versuchen, zuzugreifen. Also, wenn mein convertView != null (die sonst zu Fall) greift auf die Elemente auf dem Layout über unsere ViewHolder und wenn die vorherige Ansicht ein Separator war es natürlich nicht funktioniert, eine Textview dort zuzugreifen, die nur auf den „echten“ Veröffentlichungen sind das Layout .

So zwinge ich auch meinen getView() das Layout nicht nur, wenn convertView == null, aufzuzublasen, sondern auch, wenn die vorherige listRow ist anders als die aktuelle: if (convertView == null || (listRow != listRow_previous)) { [....] }

Das scheint jetzt fast zu arbeiten. Oder zumindest nicht zum Absturz bringt es nicht von Anfang an. Aber es stürzt immer noch, und ich weiß nicht, was ich habe anderes zu tun. Ich habe versucht, in convertView.getID() und convertView.getResources() zu sehen, aber das war nicht wirklich so weit hilfreich. Vielleicht hat jemand andere hat eine Idee, wie ich meinen aktueller convertView entspricht das Listenelement Layout oder das Listentrenn Layout prüfen, ob. Danke.

Hier ist der Code. Wo auch immer es ist ein [...] ich einige weniger wichtige Code nahm, um es einfacher zu lesen und zu verstehen:

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

Und hier meine Logcat Ausgabe:

  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: android.content.res.Resources@437613e0                                  
  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: android.content.res.Resources@437613e0                                       
  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: android.content.res.Resources@437613e0                                  
  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: android.content.res.Resources@437613e0                                       
  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: android.content.res.Resources@437613e0                                                    
  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: android.content.res.Resources@437613e0                                                    
  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: android.content.res.Resources@437613e0                                                    
  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: android.content.res.Resources@437613e0                                  
  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: android.content.res.Resources@437613e0                                       
  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: android.content.res.Resources@437613e0                                  
  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: android.content.res.Resources@437613e0                                       
  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: android.content.res.Resources@437613e0                                                    
  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: android.content.res.Resources@437613e0                                                    
  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)    
War es hilfreich?

Lösung

Sie haben vergessen, ein paar Methoden, die Sie brauchen außer Kraft zu setzen: getViewTypeCount () und getItemViewType () . Diese sind nicht für Listen erforderlich, in denen alle Zeilen gleich sind, aber sie sind sehr wichtig für Ihr Szenario. Implementieren Sie diese richtig und Android wird beibehalten separate Objekt-Pools für Ihre Kopf- und Detailzeilen.

Oder könnten Sie sehen:

Andere Tipps

Durch den Hinweis mit getViewTypeCount () und getItemViewType () es funktioniert perfekt jetzt.

Die Umsetzung dieser beiden Methoden ist sehr einfach:

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

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

Wie commonsware in seiner Antwort erwähnt auf diese Weise Android werden verschiedene Objektpools für unterschiedliche Listenelemente beibehalten, die auch bedeutet, dass Sie die Prüfung für listRow_previous in meinem Beispiel entfernen und die if (convertView == null || (listRow != listRow_previous)) nur if (convertView == null) ändern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top