title: Generic recycleview adapter with header footer
body: <p>I have created a generic <code>Recycleview</code> Adapter with a header and a footer. I highly appreciate if someone could go through it, because i am getting <code>IndexOutOfBoundsException</code> exception on             <code>viewHolder.mRowFooter.showData(mFooterData);</code>.</p>
  <p>Also is it a good approach? Any suggestions are highly appreciated.</p>
  <pre><code>/**
   * @param &lt;T&gt; generic type for List item
   * @param &lt;V&gt; generic type for header
   * @param &lt;E&gt; generic type for footer
   */
  public class RecyclerViewGenericAdapter&lt;T, V, E&gt; extends RecyclerView.Adapter&lt;RecyclerView.ViewHolder&gt; {
      private ArrayList&lt;T&gt; mDataset;
      private V mHeaderData;
      private E mFooterData;
  
      private static final int TYPE_HEADER = 000;
      private static final int TYPE_ITEM = 111;
      private static final int TYPE_FOOTER = 222;
  
      private OnItemClickListener&lt;T&gt; onItemClickListener;
      private OnItemClickListenerHeader&lt;V&gt; onItemClickListenerHeader;
      private OnItemClickListenerFooter&lt;E&gt; onItemClickListenerFooter;
  
      private int layoutId, layoutIdHeader, layoutIdFooter;
  
      public RecyclerViewGenericAdapter(ArrayList&lt;T&gt; mDataset,int layoutId, V mHeaderData,int layoutIdHeader,
                                        E mFooterData, int layoutIdFooter, OnItemClickListener&lt;T&gt; onItemClickListener,
                                        OnItemClickListenerHeader onItemClickListenerHeader, OnItemClickListenerFooter onItemClickListenerFooter) {
          this.onItemClickListener = onItemClickListener;
          this.onItemClickListenerHeader = onItemClickListenerHeader;
          this.onItemClickListenerFooter = onItemClickListenerFooter;
          this.mDataset = mDataset;
          this.mHeaderData = mHeaderData;
          this.mFooterData = mFooterData;
          this.layoutId = layoutId;
          this.layoutIdHeader = layoutIdHeader;
          this.layoutIdFooter = layoutIdFooter;
  
      }
  
      @Override
      public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
          RecyclerView.ViewHolder vh = null;
          if (viewType == TYPE_ITEM) {
              RecyclerViewRow&lt;T&gt; row = (RecyclerViewRow&lt;T&gt;) LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
              vh = new ItemViewHolder(row);
          }else if (viewType == TYPE_HEADER) {
              RecyclerViewRowHeader&lt;V&gt; rowHeader = (RecyclerViewRowHeader&lt;V&gt;) LayoutInflater.from(parent.getContext()).inflate(layoutIdHeader, parent, false);
              vh = new HeaderViewHolder(rowHeader);
          } else if(viewType == TYPE_FOOTER) {
              RecyclerViewRowFooter&lt;E&gt; footerRow = (RecyclerViewRowFooter&lt;E&gt;) LayoutInflater.from(parent.getContext()).inflate(layoutIdFooter, parent, false);
              vh = new FooterViewHolder(footerRow);
          }
          return vh;
      }
  
      @Override
      public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
          if (holder instanceof RecyclerViewGenericAdapter.ItemViewHolder) {
              ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
              itemViewHolder.onBind((mHeaderData!=null? position-1 : position), itemViewHolder);
          } else if (holder instanceof RecyclerViewGenericAdapter.HeaderViewHolder) {
              HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
              headerViewHolder.onBind(headerViewHolder);
          } else if (holder instanceof RecyclerViewGenericAdapter.FooterViewHolder) {
              FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
              footerViewHolder.onBind(footerViewHolder);
          }
      }
  
      @Override
      public int getItemCount() {
          if (mHeaderData != null &amp;&amp; mFooterData != null) {
              return mDataset.size() + 2;
          } else if (mHeaderData != null || mFooterData != null) {
              return mDataset.size() + 1;
          }
          return mDataset.size();
      }
  
      @Override
      public int getItemViewType(int position) {
          if (position == 0 &amp;&amp; mHeaderData!=null) {
              return TYPE_HEADER;
          } else if (position == mDataset.size()+1 &amp;&amp; mFooterData!=null) {
              return TYPE_FOOTER;
          } else {
              return TYPE_ITEM;
          }
      }
  
      /**
       * Item ViewHolder
       **/
      public class ItemViewHolder extends RecyclerView.ViewHolder {
          public RecyclerViewRow&lt;T&gt; mRow;
  
          public ItemViewHolder(RecyclerViewRow&lt;T&gt; itemView) {
              super((View) itemView);
              mRow = itemView;
          }
  
          private void onBind(final int position, ItemViewHolder viewHolder) {
  
              viewHolder.mRow.showData(mDataset.get(position));
              ((View) viewHolder.mRow).setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      if (onItemClickListener != null) {
                          onItemClickListener.onItemClick(mDataset.get(position));
                      }
                  }
              });
          }
      }
  
      public interface RecyclerViewRow&lt;T&gt; {
          void showData(T item);
      }
  
      public interface OnItemClickListener&lt;T&gt; {
          void onItemClick(T position);
      }
  
      /**
       * Header ViewHolder
       **/
      public class HeaderViewHolder extends RecyclerView.ViewHolder {
          public RecyclerViewRowHeader&lt;V&gt; mRowHeader;
  
          public HeaderViewHolder(RecyclerViewRowHeader&lt;V&gt; itemView) {
              super((View) itemView);
              mRowHeader = itemView;
          }
  
          private void onBind(HeaderViewHolder viewHolder) {
              viewHolder.mRowHeader.showData(mHeaderData);
              ((View) viewHolder.mRowHeader).setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      if (onItemClickListenerHeader != null) {
                          onItemClickListenerHeader.onItemClickHeader(mHeaderData);
                      }
                  }
              });
          }
      }
  
      public interface RecyclerViewRowHeader&lt;V&gt; {
          void showData(V item);
      }
  
      public interface OnItemClickListenerHeader&lt;V&gt; {
          void onItemClickHeader(V position);
      }
  
      /**
       * Footer ViewHolder
       **/
      public class FooterViewHolder extends RecyclerView.ViewHolder {
          public RecyclerViewRowFooter&lt;E&gt; mRowFooter;
  
          public FooterViewHolder(RecyclerViewRowFooter&lt;E&gt; itemView) {
              super((View) itemView);
              mRowFooter = itemView;
          }
  
          private void onBind(FooterViewHolder viewHolder) {
              viewHolder.mRowFooter.showData(mFooterData);
              ((View) viewHolder.mRowFooter).setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      if (onItemClickListenerFooter != null) {
                          onItemClickListenerFooter.onItemClickFooter(mFooterData);
                      }
                  }
              });
          }
      }
  
      public interface RecyclerViewRowFooter&lt;E&gt; {
          void showData(E item);
      }
  
      public interface OnItemClickListenerFooter&lt;E&gt; {
          void onItemClickFooter(E position);
      }
  
  }
  </code></pre>
  <p>complete code is on <a href="https://github.com/amirdora/GenericRecycleViewAdapter/tree/Recycleview_HeaderFooter" rel="nofollow noreferrer">GitHub</a></p>