1

Ich erhalte eine IndexOutOfBoundsException, wenn ich versuche, den Ansichtstyp als Funktion der Position der Daten in meinem Array zurückzugeben. Ich habe zwei Datenquellen. Einer ist eine Werbung und der andere ist eine Liste von Namen und Orten. Muss ich die Arrays zu einem einzigen Array kombinieren, bevor ich sie im RecyclerAdapter verarbeite? Ich würde es lieber nicht tun, besonders wenn sie im Prinzip verschiedene Typen sein könnten, d. H. Bilder gegen Text. Meine getItemCount() Methode gibt die summierte Größe der beiden Arrays korrekt zurück. Warum bekomme ich diese Ausnahme? Wie kann ich das gewünschte Ergebnis erzielen, wenn Daten aus zwei verschiedenen Quellen in zwei verschiedenen Ansichtstypen angezeigt werden?IndexOutOfBoundsException in RecyclerAdapter mit mehreren Ansichtstypen

Meine Haupttätigkeit:

public class MainActivity extends AppCompatActivity { 

    private ArrayList<Object> getPresidentsArrayList() { 
     ArrayList<Object> items = new ArrayList<>(); 
     items.add(new President("George Washington", "Mount Vernon")); 
     items.add(new President("John Adams", "Braintree")); 
     items.add(new President("Thomas Jefferson", "Monticello")); 
     items.add(new President("James Madison", "Port Conway")); 
     return items; 
    } 

    private ArrayList<Object> getAdsArrayList() { 
     ArrayList<Object> ads = new ArrayList<>(); 
     ads.add(new Sponsored("Craft Beer 20% Off", "Budweiser")); 
     ads.add(new Sponsored("Craft Beer 20% Off", "Budweiser")); 
     ads.add(new Sponsored("Craft Beer 20% Off", "Budweiser")); 
     ads.add(new Sponsored("Craft Beer 20% Off", "Budweiser")); 
     return ads; 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 
     recyclerView.setLayoutManager(new LinearLayoutManager(this)); 
     bindDataToAdapter(recyclerView); 

    } 

    private void bindDataToAdapter(RecyclerView recyclerView) { 
     recyclerView.setAdapter(new HeterogeneousRecyclerAdapter(getPresidentsArrayList(), getAdsArrayList())); 
    } 

} 

Mein Recycler Adapter für mehrere Ansichten ermöglicht:

public class HeterogeneousRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 

    private List<Object> items; 
    private List<Object> ads; 
    private final int PRESIDENT = 0, SPONSORED = 1; 

    public HeterogeneousRecyclerAdapter(List<Object> items, List<Object> ads) { 
     this.items = items; 
     this.ads = ads; 
    } 

    @Override 
    public int getItemCount() { 
     return (this.items.size() + this.ads.size()); 
    } 

    @Override 
    public int getItemViewType(int position) { 
     if (items.get(position) instanceof President) { 
      return PRESIDENT; 
     } else if (ads.get(position) instanceof Sponsored) { 
      return SPONSORED; 
     } 
     return -1; 
    } 

    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { 

     RecyclerView.ViewHolder viewHolder; 
     LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); 

     switch (viewType) { 
      case PRESIDENT: 
       View v1 = inflater.inflate(R.layout.layout_viewholder1, viewGroup, false); 
       viewHolder = new ViewHolder1(v1); 
       break; 
      case SPONSORED: 
       View v2 = inflater.inflate(R.layout.layout_viewholder2, viewGroup, false); 
       viewHolder = new ViewHolder2(v2); 
       break; 
      default: 
       View v = inflater.inflate(android.R.layout.simple_list_item_1, viewGroup, false); 
       viewHolder = new RecyclerViewSimpleTextViewHolder(v); 
       break; 
     } 
     return viewHolder; 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 
     switch (viewHolder.getItemViewType()) { 
      case PRESIDENT: 
       ViewHolder1 vh1 = (ViewHolder1) viewHolder; 
       configureViewHolder1(vh1, position); 
       break; 
      case SPONSORED: 
       ViewHolder2 vh2 = (ViewHolder2) viewHolder; 
       configureViewHolder2(vh2, position); 
       break; 
      default: 
       RecyclerViewSimpleTextViewHolder vh = (RecyclerViewSimpleTextViewHolder) viewHolder; 
       configureDefaultViewHolder(vh, position); 
       break; 
     } 
    } 

    private void configureDefaultViewHolder(RecyclerViewSimpleTextViewHolder vh, int position) { 
     vh.getLabel().setText((CharSequence) items.get(position)); 
    } 

    private void configureViewHolder1(ViewHolder1 vh1, int position) { 
     President president = (President) items.get(position); 
     if (president != null) { 
      vh1.getLabel1().setText(president.getName()); 
      vh1.getLabel2().setText(president.getHometown()); 
     } 
    } 

    private void configureViewHolder2(ViewHolder2 vh2, int position) { 
     Sponsored sponsored = (Sponsored) ads.get(position); 
     if (sponsored != null) { 
      vh2.getLabel1().setText(sponsored.getName()); 
      vh2.getLabel2().setText(sponsored.getCompany()); 
     } 
    } 
} 

Antwort

3

Sie brauchen eine gemeinsame Liste zu erstellen, sowohl Ihre Liste hinzufügen. Tun Sie einfach das folgende -

public HeterogeneousRecyclerAdapter(List<Object> items, List<Object> ads) { 
     this.items = items; 
     items.addAll(ads); 
    } 

Nun ist die get Artikel zählen ändern -

@Override 
public int getItemCount() { 
    return this.items.size(); 
} 

Hoffe, dass es für Sie in Ordnung arbeiten :)

+0

Wo würde ich "Anzeigen" zu meiner Artikelliste hinzufügen? – santafebound

+0

Nur in der letzten Zeile des Konstruktors des Adapters. Keine Notwendigkeit, Referenzen von Anzeigen jetzt zu halten. – Neo

+0

Okay, ich habe es, so '' public HeterogeneousRecyclerAdapter (Liste Artikel, Liste Anzeigen) { this.items = Artikel; items.addAll (Anzeigen); } '' und dann referenzieren Sie einfach '' items''. – santafebound

2

Die Umsetzung Ihrer getItemCount falsch ist

@Override 
public int getItemCount() { 
    return (this.items.size() + this.ads.size()); 
} 

Wenn beide nicht 0 zurückgeben, geben Sie einen Wert zurück, der größer als die Größe beider Sammlungen ist. Aus diesem Grund erhalten Sie eine ArrayIndexOutBoundException. Denken Sie daran, dass position geht 0-getItemCount - 1 und in Ihrem Fall, weder items noch ads enthalten getItemCount Objekte

1

Die Umsetzung Ihrer getItemViewType falsch ist. Nehmen wir an, Ihre items Liste hat 4 Artikel und ads hat 3 Werbeobjekte. Jetzt wird Ihre zurückgeben 7. Jetzt beginnt das System den Artikeltyp dieser 7 Objekte zu finden. Nehmen wir an, es möchte den Typ der 5. Zeile in RecyclerView finden. Also jetzt in Ihrer Methode getItemViewType Zeile Nummer 1 selbst diese Ausnahme werfen, weil die Größe items Liste ist nur 4.

Entweder müssen Sie diese beiden Listen in einer Liste zusammenfassen oder eine Reihenfolge unter den Recycler-Ansichten haben, so wie alle Anzeigen vor den Artikeln erscheinen. In diesem Fall müssen Sie auch Ihre getItemViewType ändern.

Hoffe, das hilft.