1

Я получаю исключение IndexOutOfBoundsException при попытке вернуть тип вида в зависимости от положения данных в моем массиве. У меня есть два источника данных. Один - это реклама, а другой - список имен и мест. Нужно ли объединять массивы в один массив, прежде чем обрабатывать его в RecyclerAdapter? Я бы предпочел, особенно, если в принципе они могут быть разных типов, то есть изображений и текста. Мой метод getItemCount() правильно возвращает суммированный размер двух массивов. Почему я получаю это исключение? Как я могу достичь желаемого результата отображения данных из двух разных источников в двух разных типах представлений?IndexOutOfBoundsException в RecyclerAdapter с несколькими типами просмотра

Моя основная деятельность:

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

} 

Мой утилизатор адаптер позволяет несколько представлений:

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

ответ

3

Вы должны создать общий список, добавив оба списка. Просто сделайте следующее -

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

Теперь изменяет подсчитать прибудет Предмет -

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

Надеется, что он будет работать нормально для вас :)

+0

Где я могу добавить объявления в список своих товаров? – santafebound

+0

Только в последней строке конструктора адаптера. Теперь нет необходимости хранить ссылки на рекламу. – Neo

+0

Хорошо, так что '' public HeterogenicRecyclerAdapter (список элементов, список объявлений) { this.items = items; items.addВсе (объявления); } ', а затем просто ссылайтесь на' 'элементы''. – santafebound

2

реализации Вашего getItemCount неправильно

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

, если оба не возвращают 0, вы возвращаете значение, большее размера обоих коллекций. Вот почему вы получаете исключение ArrayIndexOutBoundException. Помните, что position идет от 0 к getItemCount - 1 и, в вашем случае, ни items, ни ads содержат getItemCount объекты

1

Реализации вашего getItemViewType неправильно. Предположим, ваш items Список содержит 4 товаров и ads имеет 3 рекламных объекта. Теперь ваш getItemViewType вернется 7. Теперь система начнет искать тип элемента этих 7 объектов. Предположим, он хочет найти тип 5-й строки в RecyclerView. Итак, теперь в вашем методе getItemViewType строка номер 1 сама выбрасывает это исключение, потому что размер items Список - только 4.

Либо вам придется объединить эти два списка в одном списке или иметь некоторый порядок среди элементов вида ресайклеров, как и все рекламные объявления, которые будут отображаться перед элементами. В этом случае вам также придется изменить свой getItemViewType.

Надеюсь, это поможет.