A Guide to Android RecyclerView and CardView

11 Francesco Azzola Oct 22, 2014

The new support library in Android L introduced two new UI widgets: RecyclerView and CardView. The RecyclerView is a more advanced and more flexible version of the ListView. This new component is a big step because the ListView is one of the most used UI widgets. The CardView widget, on the other hand, is a new component that does not "upgrade" an existing component. In this tutorial, I'll explain how to use these two widgets and show how we can mix them. Let's start by diving into the RecyclerView.

RecyclerView: Introduction

As I mentioned, RecyclerView is more flexible that ListView even if it introduces some complexities. We all know how to use ListView in our app and we know if we want to increase the ListView performances we can use a pattern called ViewHolder. This pattern consists of a simple class that holds the references to the UI components for each row in the ListView. This pattern avoids looking up the UI components all the time the system shows a row in the list. Even if this pattern introduces some benefits, we can implement the ListView without using it at all. RecyclerView forces us to use the ViewHolder pattern. To show how we can use the RecyclerView, we can suppose we want to create a simple app that shows a list of contact cards. The first thing we should do is create the main layout. RecyclerView is very similar to the ListView and we can use them in the same way:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:paddingLeft="@dimen/activity_horizontal_margin"
      android:paddingRight="@dimen/activity_horizontal_margin"
      android:paddingTop="@dimen/activity_vertical_margin"
      android:paddingBottom="@dimen/activity_vertical_margin"
      tools:context=".MyActivity">
      <android.support.v7.widget.RecyclerView
             android:id="@+id/cardList"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
       />    
</RelativeLayout>

As you'll notice from the layout shown above, the RecyclerView is available in the Android support library, so we have to modify build.gradle to include this dependency:

dependencies {
       ...    
       compile 'com.android.support:recyclerview-v7:21.0.0-rc1'
 }

Now, in the onCreate method we can get the reference to our RecyclerView and configure it:

@Override
protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_my);
      RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
      recList.setHasFixedSize(true);
      LinearLayoutManager llm = new LinearLayoutManager(this);
      llm.setOrientation(LinearLayoutManager.VERTICAL);
      recList.setLayoutManager(llm);
}

If you look at the code above, you'll notice some differences between the RecyclerView and ListView. RecyclerView requires a layout manager. This component positions item views inside the row and determines when it is time to recycle the views. The library provides a default layout manager called LinearLayoutManager.

CardView

The CardView UI component shows information inside cards. We can customise its corners, the elevation and so on. We want to use this component to show contact information. These cards will be the rows of RecyclerView and we will see later how to integrate these two components. By now, we can define our card layout:

<android.support.v7.widget.CardView
      xmlns:card_view="http://schemas.android.com/apk/res-auto"
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/card_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      card_view:cardCornerRadius="4dp"
      android:layout_margin="5dp">

  <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">

     <TextView
         android:id="@+id/title"
         android:layout_width="match_parent"
         android:layout_height="20dp"
         android:background="@color/bkg_card"
         android:text="contact det"
         android:gravity="center_vertical"
         android:textColor="@android:color/white"
         android:textSize="14dp"/>

    <TextView
        android:id="@+id/txtName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name"
        android:gravity="center_vertical"
        android:textSize="10dp"
        android:layout_below="@id/title"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="5dp"/>

    <TextView
        android:id="@+id/txtSurname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Surname"
        android:gravity="center_vertical"
        android:textSize="10dp"
        android:layout_below="@id/txtName"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="5dp"/>

    <TextView
        android:id="@+id/txtEmail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Email"
        android:textSize="10dp"
        android:layout_marginTop="10dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="150dp"
        android:layout_alignBaseline="@id/txtName"/>

</RelativeLayout>

As you can see, the CardView is very simple to use. This component is available in another android support library so we have to add this dependency too:

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

RecyclerView: Adapter

The adapter is a component that stands between the data model we want to show in our app UI and the UI component that renders this information. In other words, an adapter guides the way the information are shown in the UI. So if we want to display our contacts, we need an adapter for the RecyclerView. This adapter must extend a class called RecyclerView.Adapter passing our class that implements the ViewHolder pattern:

public class MyAdapter extends RecyclerView.Adapter<MyHolder> { ..... }

We now have to override two methods so that we can implement our logic: onCreateViewHolder is called whenever a new instance of our ViewHolder class is created, and onBindViewHolder is called when the SO binds the view with the data -- or, in other words, the data is shown in the UI.

In this case, the adapter helps us combine the RecyclerView and CardView. The layout we defined before for the cards will be the row layout of our contact list in the RecyclerView. Before doing it, we have to define our data model that stands at the base of our UI (i.e. what information we want to show). For this purpose, we can define a simple class:

public class ContactInfo {
      protected String name;
      protected String surname;
      protected String email;
      protected static final String NAME_PREFIX = "Name_";
      protected static final String SURNAME_PREFIX = "Surname_";
      protected static final String EMAIL_PREFIX = "email_";
}

And finally, we are ready to create our adapter. If you remember what we said before about Viewholder pattern, we have to code our class that implements it:

public static class ContactViewHolder extends RecyclerView.ViewHolder {
     protected TextView vName;
     protected TextView vSurname;
     protected TextView vEmail;
     protected TextView vTitle;

     public ContactViewHolder(View v) {
          super(v);
          vName =  (TextView) v.findViewById(R.id.txtName);
          vSurname = (TextView)  v.findViewById(R.id.txtSurname);
          vEmail = (TextView)  v.findViewById(R.id.txtEmail);
          vTitle = (TextView) v.findViewById(R.id.title);
      }
 }

Look at the code, in the class constructor we get the reference to the views we defined in our card layout. Now it is time to code our adapter:

public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {

    private List<ContactInfo> contactList;

    public ContactAdapter(List<ContactInfo> contactList) {
            this.contactList = contactList;
    }

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

    @Override
    public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
        ContactInfo ci = contactList.get(i);
        contactViewHolder.vName.setText(ci.name);
        contactViewHolder.vSurname.setText(ci.surname);
        contactViewHolder.vEmail.setText(ci.email);
        contactViewHolder.vTitle.setText(ci.name + " " + ci.surname);
   }

   @Override
   public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.
                    from(viewGroup.getContext()).
                    inflate(R.layout.card_layout, viewGroup, false);

        return new ContactViewHolder(itemView);
   }

  public static class ContactViewHolder extends RecyclerView.ViewHolder {
      ...
  }
}

In our implementation, we override onBindViewHolder where we bind the data (our contact info) to the Views. Notice that we don't look up UI components but simply use the references stored in our ContactViewHolder. In onCreateViewHolder we return our ContactViewHolder inflating the row layout (the CardView in our case).

Run the app and you'll get the results shown below:

Android RecyclerView with Cardview

The source code is available @github

11 comments


Or enter your name and Email
  • L liyong 2 years ago
    Most helpful ! But I have a trouble about the corner.The CardView has a radius corner,and the TextView for title has a right angle.It is very ugly.How can I get the same effects with you? Help me!
  • P Priya 2 years ago
    Very nice tutorial..clearly explained
  • C Chester.S 2 years ago
    Most helpful
  • A arun 2 years ago
    I need to implement to do something on selecting the item, help me!
  • K Kevin 3 years ago
    By the way, good tutorial, I love it
  • K Kevin 3 years ago
    MainActivity.java onCreate(){ .... ContactAdapter ca = new ContactAdapter(createList(30)); recList.setAdapter(ca); } private List createList(int size) { List result = new ArrayList(); for (int i=1; i <= size; i++) { ContactInfo ci = new ContactInfo(); ci.name = ContactInfo.NAME_PREFIX + i; ci.surname = ContactInfo.SURNAME_PREFIX + i; ci.email = ContactInfo.EMAIL_PREFIX + i + "@test.com"; result.add(ci); } return result; }
  • FA Francesco Azzola 3 years ago
    Thx for your suggestions! The source code is available @github. You can find the link at the article end.
  • MA matthew arnold 3 years ago
    There is some code missing at the end that implements the contactAdapter into the MainActivity. There are a couple of comments here already to this effect :( Otherwise this is a fantastic tutorial. But could you update the missing part because im stuck otherwise :) Thank you
  • CA Chris Aardal 3 years ago
    Can anyone tell me how to initiate the adapter in my activity's onCreate method?
    • MA matthew arnold 3 years ago
      I am having the same issue. It seems there is some small amount of code missing :(
  • CA Chris Aardal 3 years ago
    Can u post the full code ? Awsome job btw :) Problem is to see how you manage the adapterclass in your activity. Thanks alot