How to display an ArrayList in a RecyclerView?

android, android-adapter, android-recyclerview, arraylist, java

Solution

I remember when I was first reading about `RecyclerView`s - I agree it can be a little confusing at first. Hopefully, this explanation will help you understand it better.

RecyclerView basics

1. Adding the `RecyclerView`

First you need to add your `RecyclerView` to your XML layout. I'm assuming you know how to do this. You also declare it in your Java code:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);

2. Creating the `Adapter` and understanding `ViewHolder`

Next, you need to create an `Adapter` for it. This is a class that implements `RecyclerView.Adapter<YourAdapter.YourViewHolder>`. I will explain what this means in a minute.

I believe it helps to look at an example of an `Adapter` to understand how it works (e.g. one I created for an open-source app). I would also highly recommend looking through a set of Java files I have made as an example on Gist on GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

I will be referencing the example files from the link above in this explanation so you can follow along.

You can see that the `Adapter` class contains an inner class, which is your `ViewHolder`. Therefore, it needs to extend `RecyclerView.ViewHolder`.

Inside this `ViewHolder`, you declare the variables for the layouts that will be used for each list item in your `RecyclerView`. In the constructor for your `ViewHolder`, you assign these variables. I'm referring to this part of the code (I'm giving my example below):

ExampleViewHolder(View itemView) {
    super(itemView);
    text1 = (TextView) itemView.findViewById(R.id.text1);
    text2 = (TextView) itemView.findViewById(R.id.text2);
}

That's all you need for your `ViewHolder` (the inner class in your `Adapter`).

3. Understanding the `Adapter`

Like most Java objects, you will need to have a constructor some private variables in your `Adapter` class. Here are mine:

private ArrayList<CustomClass> mCustomObjects;

public ExampleAdapter(ArrayList<CustomClass> arrayList) {
    mCustomObjects = arrayList;
}

You will need to have your `ArrayList<CustomClass>` as a constructor parameter so you can pass the list so your `Adapter` can use it.

If you look at the rest of the `Adapter` class, it contains some methods which it overrides from what it extends. Let's have a quick look at what these are:

- `getItemCount()` returns the size of your list.

- `onCreateViewHolder(...)` is used to inflate the layout for your list item.

- `onBindViewHolder(...)` configures your layouts for the list item (e.g. setting text to a `TextView`)

For most cases, `getItemCount()` will just return the `size()` of your `ArrayList<CustomClass>`.

The `onCreateViewHolder(...)` method generally stays the same too:

@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_2, parent, false);
    return new ExampleViewHolder(view);
}

You can see that I am inflating the layout that I will use as my list item (`android.R.layout.simple_list_item_2`). This layout is built in to Android so I don't need to create it - of course, your can use whatever layout you wish and then modify your `Adapter` for widgets that you may be using. The return type of this method will match whatever you named your `ViewHolder` inner class.

Now, the interesting bit is in `onBindViewHolder(...)`. You configure your layouts here, so it is completely up to you what you want to do. Here's a template you could use:

@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
    CustomClass object = mCustomObjects.get(position);

    String firstText = object.getFirstText()
    String secondText = object.getSecondText()

    holder.text1.setText(firstText);
    holder.text2.setText(secondText);
}

Basically, you access your `ViewHolder` variables (for the widgets in your list item layout) by doing `holder.myWidget`. The `holder` part is coming from the parameter, which is your `ViewHolder` we talked about earlier, and `myWidget` would be the name of the `View` variable from that.

In the example above, the `object` has a `getFirstText()` method, and the `ViewHolder` contains a `TextView` (`text1`), so I am setting the text.

There is also one more method - `onAttachedToRecyclerView(...)`. You can use this for more complex things, but at a basic level, it is usually this:

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

4. Configuring `RecyclerView`

Remember at the beginning, when we declared and assigned our `RecyclerView`?:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);

Now we are going to configure it.

You start by setting a "layout manager". This determines how each list item will be displayed on screen. The common ones are `LinearLayoutManager` and `GridLayoutManager`. The former puts your list items into a standard list (nothing special really, but it is very useful), and the latter organises your list items into a grid type of layout.

In our example, we're going to use a `LinearLayoutManager`. To set this on the `RecyclerView`, we do this:

recyclerView.setLayoutManager(new LinearLayoutManager(this));

That's all.

And all we have to do next is to set the `Adapter` class we created and customised earlier to your `RecyclerView`:

ExampleAdapter adapter = new ExampleAdapter(yourCustomArrayList);
recyclerView.setAdapter(adapter);

In the above, I'm assuming your `adapter` only has one parameter, but this will depend on how you configured it earlier.

5. Using your `RecyclerView`

The steps above should give you a working `RecyclerView`. If you get stuck, you can look at how I added one into my app here.

You can also look through the Google samples for the `RecyclerView` implementation.

I hope all of this gave you a clear idea about how `RecyclerView` works.

Adding a click listener

You may want to add a click listener so that you are not using the `RecyclerView` just for displaying items.

To do this, your inner `ViewHolder` class needs to implement `View.OnClickListener`. This is because you will set an `OnClickListener` to the `itemView` parameter of the `ViewHolder`'s constructor. Let me show you what I mean:

public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

The only other things you need to add are a custom interface for your `Adapter` and a setter method:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

So your new, click-supporting `Adapter` is complete.

Now, let's use it...

ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
    @Override
    public void onEntryClick(View view, int position) {
        // stuff that will happen when a list item is clicked
    }
});
recyclerView.setAdapter(clickAdapter);

It's basically how you would set up a normal `Adapter`, except that you use your setter method that you created to control what you will do when your user clicks a particular list item.

To reiterate, you can look through a set of examples I made on this Gist on GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

Problem

I need to add an `Activity` where I can list the elements of an `ArrayList<CustomClass>` and I've seen there's a newer and better way to display lists - `RecyclerView`. My question is how to implement this into my app. I've found that I need to use an `Adapter`, but I don't quite understand how to implement the whole process correctly. If you're wondering, I'm referring to this examples of the docs, which I have been reading. EDIT: After having updated my code, it says it cannot resolve the symbol `setOnEntryClickListener`: ``` public class voting extends Activity { RecyclerView myList; private ArrayList<Player> players; // Players @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_voting); Intent intent = this.getIntent(); Bundle bundle = intent.getExtras(); players = (ArrayList<Player>)bundle.getSerializable("PLAYERS"); myList = (RecyclerView) findViewById(R.id.charactersList); myList.setLayoutManager(new LinearLayoutManager(this)); CoursesAdapter adapter = new CoursesAdapter(players); myList.setAdapter(adapter); } // OR RecyclerView with a click listener CoursesAdapter clickAdapter = new CoursesAdapter(players); clickAdapter.setOnEntryClickListener(new CoursesAdapter.OnEntryClickListener() { @Override public void onEntryClick(View view, int position) { // stuff that will happen when a list item is clicked } }); recyclerView.setAdapter(clickAdapter); } ``` So I've thought I had put that `interface` in the wrong place (very probably), infact I've put it in the Adapter class, at the end of it, right after the `onAttachedToRecyclerView()` Method: ``` @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } private OnEntryClickListener mOnEntryClickListener; public interface OnEntryClickListener { void onEntryClick(View view, int position); } public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) { mOnEntryClickListener = onEntryClickListener; } } ```

Original source

Related problems