Android Core

A Guide to Android RecyclerView and CardView

The new support library in Android L (Lollipop) 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'

}

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.

CardViewThe 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'
   compile 'com.android.support:recyclerview-v7:21.0.0'
}

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 ContactViewHolderinflating the row layout (the CardView in our case). Run the app and you’ll get the results shown below:

android_recyclerview_cardview

  • Source code available @ github
  • .

Reference: A Guide to Android RecyclerView and CardView from our JCG partner Francesco Azzola at the Surviving w/ Android blog.

Francesco Azzola

He's a senior software engineer with more than 15 yrs old experience in JEE architecture. He's SCEA certified (Sun Certified Enterprise Architect), SCWCD, SCJP. He is an android enthusiast and he has worked for long time in the mobile development field.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button