Mobile
Article

Mastering Complex Lists with the Android RecyclerView

By Valdio Veliu

The RecyclerView was introduced with Google’s material design in Android 5.0 Lollipop.

If you are getting started with Android development or are already an experienced developer the RecyclerView is something worth investigating.

The idea of view recycling has been in Android since version 1 in the form of the ListView. The idea is simple, to present large collection of data using a small collection of views, by recycling and rebinding these views.

The RecyclerView is a more flexible pattern of view recycling than ListViews and GridViews. What differentiates the RecyclerView from its predecessors is that it focuses only on recycling views. All the other actions needed to create a view, like how to present data set or inflate the views are delegated to the pluggable classes and that is what makes it so flexible. The hard part is setting up these classes to make a fully functional RecyclerView and that is what I will cover in this article.

To use the RecyclerView you need to follow the following steps:

  1. Add the support library
  2. Add the RecyclerView in the layout XML file
  3. Create a custom row Layout
  4. Create the  RecyclerView.Adapter to populate data into the RecyclerView
  5. Create the ViewHolder to provide a reference to the views for each data item
  6. Bind the Adapter to the RecyclerView in the Activity

Lets get started with RecyclerView, you can find the code for the final project on GitHub.

Add dependencies

Open build.gradle (app) and add the dependencies needed.

dependencies {
    ...
    compile 'com.android.support:cardview-v7:23.1.0'
    compile 'com.android.support:recyclerview-v7:23.1.0'
}

Sync Gradle and you are all set.

Add the RecyclerView to the layout file

<RelativeLayout
...
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

</RelativeLayout>

Create a custom row Layout

The row Layout represents the Layout of each single element displayed in the RecyclerView.

Create a file named row_layout.xml and add the following to it:

<android.support.v7.widget.CardView
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="@dimen/activity_vertical_margin"
    app:cardCornerRadius="@dimen/activity_vertical_margin"
    app:cardElevation="@dimen/activity_vertical_margin"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="16dp" />

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_toRightOf="@+id/imageView"
            android:text="Title"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/title"
            android:layout_toRightOf="@+id/imageView"
            android:text="Description" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

The RecyclerView will be a list of randomly chosen movies and a description. We need a class that represents a single RecyclerView item data, create a file named Data.java and add the following:

public class Data {
    public String title;
    public String description;
    public int imageId;

    Data(String title, String description, int imageId) {
        this.title = title;
        this.description = description;
        this.imageId = imageId;
    }

}

The RecyclerView Adapter

The RecyclerView.Adapter is similar to the Adapters used on a ListView but with a ViewHolder required to improve performance. A ListView has adapters for different sources such as the ArrayAdapter for arrays and CursorAdapter for database results. The RecyclerView.Adapter requires a custom implementation to supply data to the adapter.

The adapter has three methods.

  • onCreateViewHolder() inflates the row layout is and initializes the View Holder. Once the View Holder is initialized it manages the findViewById() methods, finding the views once and recycling them to avoid repeated calls.
  • onBindViewHolder() uses the View Holder constructed in the onCreateViewHolder() method to populate the current row of the RecyclerView with data.

Create a new file named Recycler_View_Adapter.java with the following class:

public class Recycler_View_Adapter extends RecyclerView.Adapter<View_Holder> {

    List<Data> list = Collections.emptyList();
    Context context;

    public Recycler_View_Adapter(List<Data> list, Context context) {
        this.list = list;
        this.context = context;
    }

    @Override
    public View_Holder onCreateViewHolder(ViewGroup parent, int viewType) {
        //Inflate the layout, initialize the View Holder
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
        View_Holder holder = new View_Holder(v);
        return holder;

    }

    @Override
    public void onBindViewHolder(View_Holder holder, int position) {

        //Use the provided View Holder on the onCreateViewHolder method to populate the current row on the RecyclerView
        holder.title.setText(list.get(position).title);
        holder.description.setText(list.get(position).description);
        holder.imageView.setImageResource(list.get(position).imageId);

        //animate(holder);

    }

    @Override
    public int getItemCount() {
        //returns the number of elements the RecyclerView will display
        return list.size();
    }

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

    // Insert a new item to the RecyclerView on a predefined position
    public void insert(int position, Data data) {
        list.add(position, data);
        notifyItemInserted(position);
    }

    // Remove a RecyclerView item containing a specified Data object
    public void remove(Data data) {
        int position = list.indexOf(data);
        list.remove(position);
        notifyItemRemoved(position);
    }

}

Creating the ViewHolder

The RecyclerView uses a ViewHolder to store the references to the relevant views for one entry in the RecyclerView. This solution avoids all the findViewById() method calls in the adapter to find the views to be filled with data.

Create a file named View_Holder.java with the following class:

public class View_Holder extends RecyclerView.ViewHolder {

   CardView cv;
   TextView title;
   TextView description;
   ImageView imageView;

   View_Holder(View itemView) {
       super(itemView);
       cv = (CardView) itemView.findViewById(R.id.cardView);
       title = (TextView) itemView.findViewById(R.id.title);
       description = (TextView) itemView.findViewById(R.id.description);
       imageView = (ImageView) itemView.findViewById(R.id.imageView);
   }
}

The LayoutManager

The Layout Manager attaches, measures, and lays out all the child views of the RecyclerView in real-time. As the user scrolls the view, the Layout Manager determines when new child views will be added and when the old child views will be detached and deleted.

These default implementations are available:

  • LinearLayoutManager – Displays items in a vertical or horizontal scrolling list.
  • GridLayoutManager – Displays items in a grid.
  • StaggeredGridLayoutManager – Displays items in a staggered grid.

You can create a custom LayoutManager by extending RecyclerView.LayoutManager or one of the implementations above and overriding the methods required.

Now that the RecyclerView is finished the next step is to fill it with some data. In the onCreate() method of the MainActivity class create an instance of the Recycler_View_Adapter and give this adapter the list of data and the context. The getApplication() method will provide the application context.

List<Data> data = fill_with_data();

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
Recycler_View_Adapter adapter = new Recycler_View_Adapter(data, getApplication());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

We will also need sample data, for this example I have created a default function, in a real app, this may come from a data source.

public List<Data> fill_with_data() {

    List<Data> data = new ArrayList<>();

    data.add(new Data("Batman vs Superman", "Following the destruction of Metropolis, Batman embarks on a personal vendetta against Superman ", R.drawable.ic_action_movie));
    data.add(new Data("X-Men: Apocalypse", "X-Men: Apocalypse is an upcoming American superhero film based on the X-Men characters that appear in Marvel Comics ", R.drawable.ic_action_movie));
    data.add(new Data("Captain America: Civil War", "A feud between Captain America and Iron Man leaves the Avengers in turmoil.  ", R.drawable.ic_action_movie));
    data.add(new Data("Kung Fu Panda 3", "After reuniting with his long-lost father, Po  must train a village of pandas", R.drawable.ic_action_movie));
    data.add(new Data("Warcraft", "Fleeing their dying home to colonize another, fearsome orc warriors invade the peaceful realm of Azeroth. ", R.drawable.ic_action_movie));
    data.add(new Data("Alice in Wonderland", "Alice in Wonderland: Through the Looking Glass ", R.drawable.ic_action_movie));

    return data;
}

You can find the icon files for the ic_action_movie button referenced above here.

This completes all the steps to set up a RecyclerView.

Animating recycles with ItemAnimator

So far I’ve explained all that’s needed to create your own RecyclerView and explained what each part of the RecyclerView structure does. Now lets make things more interesting with item animation.

RecyclerView.ItemAnimator is a class that defines the animations performed on items and will animate ViewGroup changes such as add/delete/select notified to the adapter. DefaultItemAnimator is a basic animation available by default with the RecyclerView.

To customize the DefaultItemAnimator add an item animator to the RecyclerView. This code does simply slows down the process of adding and removing items from the RecyclerView.

Add this after our last code in the onCreate method:

RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
recyclerView.setItemAnimator(itemAnimator);

Add view

Remove view

Another approach to animating RecyclerView items is to use Android Interpolators. According to developer.android.com, an interpolator defines the rate of change of an animation.

The following examples represent two animations I implemented using these interpolators. Save the files in /anim/ in the project resources folder.

anticipateovershoot_interpolator.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:interpolator="@android:anim/anticipate_overshoot_interpolator">
   <translate
       android:fromYDelta="-50%p"
       android:toYDelta="0"
       android:duration="2000"
       />
</set>

bounce_interpolator.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:interpolator="@android:anim/bounce_interpolator">
   <translate
       android:duration="1500"
       android:fromYDelta="-150%p"
       android:toYDelta="0"
       />
</set>

Now let’s return to the RecyclerView. Inside the RecyclerView Adapter class add the following function.

public void animate(RecyclerView.ViewHolder viewHolder) {
   final Animation animAnticipateOvershoot = AnimationUtils.loadAnimation(context, R.anim.bounce_interpolator);
   viewHolder.itemView.setAnimation(animAnticipateOvershoot);
}

If you take a closer look at the loadAnimation() method, it requires a context parameter and that’s why the Adapter’s constructor was modified in the first place. Now we can animate the RecyclerView. Inside the onBindViewHolder() method, call the animate() function and pass the holder parameter of the View_Holder class.

Run the app and test the animation. Here is how the bounce_interpolator animation works.

bounce animation

Next let’s test the anticipate_overshoot_interpolator animation, but first I’ll set the RecyclerView’s layout manager to StaggeredGrid in the Main Activity’s onCreate() method with a 2 column span and vertical scrolling.

recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));

anticipate_overshoot animation

Using this method of animation in the RecyclerView is easy. If you want new animations, just change the interpolation type in the examples above, set the parameters to your preference and you will have a new animation style.

Conclusion

The RecyclerView is a flexible pattern for view recycling eliminating the imitations of ListView and GridView by making item animations easy to set and reuse. Getting used to development with RecyclerView may need some work at first, but it’s worth your time.

If you have any questions or comments please let me know below.

  • http://SalaryNet30.com janice hamil

    Google gives you a great opportunity to earn

    98652$/WEEk at your home .If you

    are some intelligent you make many more Dollars.I am

    also earning many more, my relatives wondered to see how i settle my

    Life in few days thank GOD to you for this…You can also make cash i

    never tell a lie you should check this I am sure you shocked to see

    this amazing offer…I’m Loving it!!!! ☻ ▼ ▼ ▼

    ————————————————————————————————-

    »»»»»»»»» Go to my Account For WE

    +qqqqqqq

  • Tomer Bu

    Thanks! A Great tutorial. Just what I needed. I Tried to use animations in onBindViewHolder and got a wierd behaviours in some cases.

    • Valdio Veliu

      Thank you Tomer for your feedback.
      I don’t think there is a problem in
      adding Items to the recyclerview. Items appear properly, not when
      scrolling. I just retry my code and all works fine.

      The CardViews layout is actually redundant. Sorry about that, I started the project with a different idea in mind.

      Ripple effect is actually a cool trick, but i think you don’t have support for pre Lollipop devices.

      • Tomer Bu

        The ripple effect is available for devices with api level 11 and up.

        (When using background=”?android:attr/selectableItemBackground” and clickable = true )

        It’s using a selector drawable for older devices.

        When adding items, it is preferable to scroll to the new items.
        You can do so using recyclerView.scrollToPosition(position);

        Thanks very much for the tutorial. I enjoyed it. Your code is clean and organised so I found my way through it easily and learned what I needed.

        • Valdio Veliu

          Thank you for the nice words and for the update on the ripple effect. I haven’t had a chance to check it out properly, I will definitely do.
          Thank you

  • Vajeng Patidar

    Hi, thanks tutorial,I have following xml data under assets folder,

    /items>

    /items>

    which parsing technique is best for such xml file and wants to display category on first screen and items on second screen using recycleview.

    • Vajeng Patidar

      Hi Valdio, Thank you!
      I will try out the same. but still i am not clear to get only categories on first screen and respective items of the category on second screen..i.e onitemclick(Category row) on first screen, respective items should be displays on second screen.

      • Valdio Veliu

        With what I understand from what you just said. I would suggest you to use Fragments. one fragment with the categories and on click of one category you display the second fragment with the corresponding items. Both of the fragments contain a recyclerview and the data between the fragments is passed through the Activity.. This, I think is the best solution for you

        • Vajeng Patidar

          Thank you very much for your prompt reply, Valdio, I will try to implement the same and update you.

  • Novinyo AMEGADJE

    Wow great tutorial, I was just looking for something like this

  • ashe

    I can not find any clear tutorial than this. Thanks bruh! Great tutorial

  • Ridho perdana

    I know it’s very late but thank you for the tutorial.

    I just started to make an android apps and i found out about this recyclerview and this nice tutorial.

    I’ve a question about this, i got an error when running the application:

    “java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.widget.TextView.setText(java.lang.CharSequence)’ on a null object reference”

    It shows the error is on this line:

    @Override
    public void onBindViewHolder(View_Holder holder, int position) {

    //Use the provided View Holder on the onCreateViewHolder method to populate the current row on the RecyclerView
    holder.title.setText(list.get(position).title);
    holder.description.setText(list.get(position).description);
    holder.imageView.setImageResource(list.get(position).imageId);

    //animate(holder);

    }

    Can you help me?
    Thanks before.

    • Mostafa Hawash

      Hey,Actually i had the same error ,
      did you find a solution ?

      • Ridho perdana

        Yes i did, my problem was that i put the wrong id of my (TextView). Just re-check your id.

        • Mostafa Hawash

          Actually i realized later tham i am missing many things science im new with Android,
          Anyway Thanks a lot man , i appreciate your help ^^

  • Hector Orozco

    Hello nicely detailed. But I have a problem, I’ve followed this tutorial step by step but the reciclerview just does not apear when I run the app, it just get the white screen. I can’t find why.

  • Gabriel Ortega Rosero

    Beforehand, thanks so muchs, this tutorial was so clear and useful… Nowm Could you help me please? I’m actually using the method insert(position, object) for adding items to the list but, the animations does not appear, besides, the window does not perform the “autoscroll”, so i have to scroll down the window for see the new element added… how did you solve this?

  • Sachin Rajput

    i liked , but this is simple only man

    make an example where recycler view row is having some textview or edit text with one button on clicking of that button update that text value and then scroll , the value is misplacing can u help

  • Alvar Lagerlof

    Great tutorial, but you need to work a bit more with material design. The corners are way to rounded and the shadow is to big. A little bit for margin is needed too.

  • ARUNBALAN NV

    Scrolling RecyclerView creates duplicate items. is there any way to avoid this?

  • Ashwin Sinha

    how do u add a listview within card view… i am unable to use adapter class withing recycler view to set the list view

  • Ankit Anand

    anyway to add and delete items from the list?
    would be really helpful

    thank you

    • Valdio Veliu

      remove an item from the data list and then call

      adapter.notifyDataSetChanged();

      or

      adapter.notifyItemRemoved(index);

  • Joseph Joey

    Thanks for explaining recyclerview in such a way that a newbie will understand it properly. Great going bruh. One might ask how to set a different image for each card layout? How can it be done?

    • Valdio Veliu

      Thanks Joseph. Actually the different image can be passed on the fill_with_data() function…If you scroll to the end of the code snippet you can change the resource id ….. But this is only a demonstration.. This can be image bitmaps or even some URL to the image and the image is loaded from the adapter.

  • Ayush Shrivastava

    What if i have to add it on a tab layout? or a fragment

  • nadeem

    how to get edittext data from it

  • Mario German Agudelo

    Thank you very much for sharing your knowledge with everyone, could you help me I need to place a spinner in a recyclerview, you have some tutorial or link in which to do this process, I appreciate all your help.

  • Nirali Acharya

    Thanks..It was very helpful..

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Mobile, once a week, for free.