Display Objects of Different Types in a RecyclerView
The Interface
Let’s start by creating a Literature
interface that all our objects will implement. In the interface
we will add a getType()
method and some constants that represent the different types. i.e. TYPE_MAGAZINE
.
public interface Literature { int TYPE_BOOK = 101; int TYPE_MAGAZINE = 102; int TYPE_NEWSPAPER= 103; int getType();}
Now, in each of our objects, let’s implement the Literature
interface, override the getType()
method, and return the correct type for that object.
The RecyclerView.Adapter
First, let’s add our List
of Literature
s as a member variable in the Adapter
.
public class LiteratureAdapter extends RecyclerView.Adapter { private List<Literature> mLiteratureList;}
We will also need three ViewHolder
s as inner classes in the Adapter
. One for each object type.
We’ll need to override four methods in the RecyclerView.Adapter
. The first of which is getItemViewType()
. This will look at an item in mLiteratureList
and determine if it’s a Book
, Magazine
, or Newspaper
then pass that result to onCreateViewHolder()
@Overridepublic int getItemViewType(int position) { return mLiteratureList.get(position).getType();}
In onCreateViewHolder()
we’ll create a new ViewHolder
depending on the type sent from getItemViewType()
. Note: In most use cases, you will also have to create a separate layout resource for each ViewHolder
.
In onBindViewHolder()
call getItemViewType()
manually. Depending on the type that it returns, cast the generic ViewHolder
parameter to the appropriate type and call its bindView()
method.
The code in getItemCount()
is going to look the same as in your standard RecyclerView.Adapter
.
@Overridepublic int getItemCount() { if (mLiteratureList == null) { return 0; } else { return mLiteratureList.size(); }}
Setting the data
The following setter is possible, butNOT recommended.
public void setLiteratureList(List<Literature> literatureList) { mLiteratureList = literatureList; notifyDataSetChanged();}
The problem with this approach is either:
a. In other parts of you app you will have to deal with Literature
objects. Which means you will constantly have to check the type and cast them appropriately to get at the data and methods.
or
b. You will need to cast your List
to a List<Literature>
before you can use the setter.
Another option is to accept any class that implements our Literature
interface, then replace the contents of mLiteratureList
.
public void setLiteratureList(List<? extends Literature> literatureList) { if (mLiteratureList == null){ mLiteratureList = new ArrayList<>(); } mLiteratureList.clear(); mLiteratureList.addAll(literatureList); notifyDataSetChanged();}
By following this method, you are able to use a List
of Book
s, Magazine
s, or Newspaper
s as the parameter.