RecyclerView Implementation. Part — 3.1.

Dhruvam Sharma
AndroidPub
Published in
10 min readJan 16, 2018
Just an easy layout,isn’t it?

Hi there, I am Dhruvam at your service again. If you’re joining me from this tutorial, kindly read the part -1 and part-2 too and then start with this one. With this tutorial, specifically, we are going to implement RecyclerView in Java. This is the most updated tutorial on RecyclerView and the one you should definitely read and bookmark. ;)

Before we begin, I would love for you to try my latest gaming application that implements all of the features that I am going to talking in this series. Any feedback is appreciated. Open this link in your mobile, if possible.
Try it:
Gamezop

Gamezop — A Gaming Platform.

This tutorial is rather a long one and you need to sit tight through. I’ve explained each bit of code and also added the github repo link, if you directly want to jump into the code.
Each java class or xml file is broken for the explanation but later is joined together to provide you the full code.

To begin with, let’s list the items of the recipe, the recipe for a beautiful RecyclerView.

What are we going to make in this tutorial?

I know, I know. How simple and not so beautiful this looks. Yes, I agree too. But this is just the simplest and the clearest implementation I could have given for explaining my point.

What we are going to learn in this tutorial?

  1. Advance Usage of Adapters.
  2. Better Understanding of ViewHolder and the LayoutManager
  3. Processes that takes place while displaying items on a RecyclerView.
  4. Horizontal and Vertical Lists.
  5. OnClickListeners
  6. Understanding RecyclerView much better.

So let’s begin with the tutorial and dive in head-first (My favorite dialogue from my favorite book -Head First Java)

Steps for implementing a basic RecyclerView

  1. Create a project
  2. Add Design Library Support
  3. Create a POJO Class
  4. Design each row
  5. Create a beautiful Adapter
  6. Handle MainActivity
  7. Handle activity_main.xml
  8. Aaand, we’re done!

If you directly want to refer the code, jump to my github project: RecyclerViewProject.

Step 1: Create A Project

Open Android Studio and click on file and create a new Project and name it RecyclerViewPart1 or whatever you want. Then click on next.

Easiest Part

Then keep on clicking next until you reach on this screen.

And hit finish. You’re done with creating a project.

Step 2: Add Design Support Library

Do this in Gradle Scripts/ build.gradle (module:app) under the dependency section.

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
.... // Add The Line Below// ....
implementation 'com.android.support:recyclerview-v7:26.1.0'

}

This is in Android Studio 3.0 (Stable Release). This is not needed though, if you’re working with Android Studio 3.0+ The Android Studio will automatically import the design library as and when needed.

Step 2: Create a POJO Class

Now, what is a POJO Class? Don’t be afraid with the name. I’ll be explaining every little item in full detail.
POJO stands for Plain Old Java Object. This means nothing. Nada. This is just a plain old class which is made by us and is used for getting and setting data in a Java Object.
Suppose we are making a List of Contacts. So there will be a database that stores the contact detail and a list that displays the contacts detail. But when passing in details to the list or storing the details into the database, these details are converted into an object and then used. These classes have getters and setters for the Contact Details. This class is basically seen in action for parsing JSON and Serialization and Deserialization. You’ll get an idea of a POJO Class from this.

So in the directory — app/java/dell.recyclerviewpart1 create a file named ContactPOJO.java. And add these details.

package dell.recylerviewpart1;

/**
* Created by dell on 16-01-2018.
*/

public class ContactPOJO {
private String mName;
private String mNumber;
private String mAddedOn;

public ContactPOJO() {} //default constructor
// Argument Constructor
public ContactPOJO(String name, String number, String addedOn) {
mName = name;
mNumber = number;
mAddedOn = addedOn;
}

public String getmAddedOn() {
return mAddedOn;
}

public String getmName() {
return mName;
}

public String getmNumber() {
return mNumber;
}

public void setmAddedOn(String mAddedOn) {
this.mAddedOn = mAddedOn;
}

public void setmName(String mName) {
this.mName = mName;
}

public void setmNumber(String mNumber) {
this.mNumber = mNumber;
}
}

Now this POJO Class does nothing in itself. It is just used for creating object and storing and retreiving Data. That’s it in a nutshell. The class I made is is self-explanatory. It just has three fields — name, addedOn and number as String Data Type. there’s nothing magic going on here. You could add fields as per your wish or need.

Step 3: Design each row

Every Column must look like something. So let’s design the row. It’s extremely simple. I’ll be using the default Constraint layout but you are free to use any Layout you wish.

Create an XML file in app/res/layout as contact_list_layout.xml And add these details into it.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="28dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@mipmap/ic_launcher_round" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="TextView"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/textView3"
app:layout_constraintStart_toEndOf="@+id/imageView" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/textView"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.0" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="TextView"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

This layout is very simple. It just seems big. It says, in a layout or a container (Constraint Layout), Add an image, and 3 TextViews. The details in each tag is just their size and margins and id. That’s nothing big. You can drag and drop and the code will automatically be generated for you. It is that easy.

It will look something like this.

Design and Layout.

Step 4: Create a beautiful Adapter

This is the most important of all the steps. Let’s create a java class in directory — app/java/dell.recyclerviewpart1 and name it CustomContactAdapter.

Our CustomContactAdatper class is currently empty. We need it to extend RecyclerView.Adaper Class and override the method according to our use.
One thing to note here is, we are not going to call the methods in our Adapter. The calling part is handled by the RecyclerView itself. We will just override the methods.

There are 3 methods we need to implement:

  1. onCreateViewHolder
  2. onBindViewHolder
  3. getItemCount

Also, we will need to create an inner class that will extend the RecyclerView.Holder. This is needed to attach each view holder to each of the row. We will study each of them one by one.

1. Class Definition

public class CustomContactAdapter extends RecyclerView.Adapter<CustomContactAdapter.MyViewHolder> {
// declaring some fields.
private ArrayList<ContactPOJO> arrayList = new ArrayList<>();
// A constructor.
public CustomContactAdapter(ArrayList<ContactPOJO> arrayList) {
this.arrayList = arrayList;
}
........
}

The class definition looks like this. our class extends the RecyclerView.Adapter and it has some weird stuff going on. The weird stuff in angle brackets say that the Adapter is going to use a ViewHolder of type MyViewHolder. It is defined in CustomContactAdapter as an inner class.

I’ve declared an array list that will retrieve data from the database. Remember I told you something like that the adapter takes stuff from the database and give it to the LayoutManager (which displays stuff on the screen)? So this is what happening in this ArrayList which stores data in the form of objects of ContactPOJO.
And there’s a constructor that receives the data from the dataset. That maybe an array, or a List or a database or internet. Anything.

Remember this?

2. InnerClass MyViewHolder

The ViewHolder does the magic here. It takes a view (each row) as a parameter and then find all the ChildViews by Id and is attached to each of the row. This is where all the data is bound to. The ViewHolder makes it easy to do all of the stuff. It is basically holder of the view.

public class CustomContactAdapter extends RecyclerView.Adapter<CustomContactAdapter.MyViewHolder> {
// declaring some fields.
private ArrayList<ContactPOJO> arrayList = new ArrayList<>();

public CustomContactAdapter(ArrayList<ContactPOJO> arrayList) {
this.arrayList = arrayList;
}
........
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView name, number, addedOn;
public MyViewHolder(View itemView) {
super(itemView);
Log.v("ViewHolder","in View Holder");
name = itemView.findViewById(R.id.textView);
number = itemView.findViewById(R.id.textView2);
addedOn = itemView.findViewById(R.id.textView3);
}
}
}

This inner class, MyViewHolder must extend the RecyclerView.ViewHolder and implement just the constructor. In this constructor, we simply find the child views of the parent view. Like each row (parent view) contains, 3 text Vews and Images (ChildViews). Here in this project I am not referring to the ImageView because it is constant. And I am not changing it at run-time. So this why I have created only 3 TextViews and not an ImageView.

3. onCreateViewHolder and onBindViewHolder

Let’s start off by learning the high level and then going deeper and then joining every piece to understand hwo this works together.

High-Level:

Whenever we start our application that has RecyclerView, It will create the total number of ViewHolders that are visible in onCreateViewHolder method and then attach ViewHolders to each row in the constructor of MyViewHolder. After this, it binds data from the ArrayList (the data set received in the constructor) to all the child views in onBindViewHolder.

Deep Insight:

In the onCreateViewHolder Method, you see something like this.

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.v("CreateViewHolder", "in onCreateViewHolder");
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.contact_list_layout,parent,false);

return new MyViewHolder(itemView);
}

What this says is, create a View and a ViewHolder which should have the contents of the type R.layout.contact_list_layout. And return the viewHolder to be attached in the constructor of the inner class.
After the ViewHolder is attached to the row, then data is attached to it from the arraylist or any data set for that matter in the onBindViewHolder.

@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Log.v("BindViewHolder", "in onBindViewHolder");
ContactPOJO contact = arrayList.get(position);
holder.name.setText(contact.getmName());
holder.number.setText(contact.getmNumber());
holder.addedOn.setText(contact.getmAddedOn());


}

You see, it takes out data from the ArrayList, and then take out the child view from the holder and attach data to it. And this ViewHolder is attached to the row itself.

So, this is how the Adapter Class looks like.

public class CustomContactAdapter extends RecyclerView.Adapter<CustomContactAdapter.MyViewHolder> {    // declaring some fields.
private ArrayList<ContactPOJO> arrayList = new ArrayList<>();

// constructor
public CustomContactAdapter(ArrayList<ContactPOJO> arrayList) {
this.arrayList = arrayList;
}
........
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView name, number, addedOn;
public MyViewHolder(View itemView) {
super(itemView);
Log.v("ViewHolder","in View Holder");
name = itemView.findViewById(R.id.textView);
number = itemView.findViewById(R.id.textView2);
addedOn = itemView.findViewById(R.id.textView3);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.v("CreateViewHolder", "in onCreateViewHolder");
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.contact_list_layout,parent,false);

return new MyViewHolder(itemView);
}



@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Log.v("BindViewHolder", "in onBindViewHolder");
ContactPOJO contact = arrayList.get(position);
holder.name.setText(contact.getmName());
holder.number.setText(contact.getmNumber());
holder.addedOn.setText(contact.getmAddedOn());
}
@Override
public int getItemCount() {
return arrayList.size();
}
}

I told you that the calling of these methods is not done by you. This actually handled by the Adapter itself.

Wait for the working now. It’s still left. Need to dive deeper still.

Step 6: Handle MainActivity.java

So ther’s not much to do in MainActivity. We just need to Add RecyclerView, LayoutManager and Adaper Objects and we’re almost done!

So let’s start.

package dell.recylerviewpart1;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

private ArrayList<ContactPOJO> mArrayList = new ArrayList<>();
private RecyclerView mRecyclerView1;
private CustomContactAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Our Stuff mRecyclerView1 = findViewById(R.id.recyclerView);


mAdapter = new CustomContactAdapter(mArrayList);

mRecyclerView1.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
mRecyclerView1.setItemAnimator( new DefaultItemAnimator());
mRecyclerView1.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
mRecyclerView1.setAdapter(mAdapter);

.....
}
.....
}

We create an ArrayList named arrayList (Duh!), w create an Adapter of type CustomContactAdapter and a brand new RecyclerView.
We find the id of the RecyclerView from the XML (We haven’t defined theXML yet, so have patience). Then pass in the data in the form of an ArrayList (our database).

Now we need to create a LayoutManager and then pass it in the setLayoutManagerMethod. The itemAnimator method is for adding animations (we’ll add some in the coming tutorials) and then the ItemDecoration for styling the row a little bit. Don’t go into the detail of this too much. Because we’ll be covering this in the next tutorial.
And then we set the adapter in the Recycler View.

Also you see, the ArrayList is empty for now, we prepare some data and add it to the ArrayList and notify the adapter that the new data has been added.

See the full code. Not much magic.

package dell.recylerviewpart1;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

private ArrayList<ContactPOJO> mArrayList = new ArrayList<>();
private RecyclerView mRecyclerView1;
private RecyclerView mRecyclerView2;
private CustomContactAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mRecyclerView1 = findViewById(R.id.recyclerView);
mRecyclerView2 = findViewById(R.id.recyclerView2);

mAdapter = new CustomContactAdapter(mArrayList);
mRecyclerView1.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
mRecyclerView1.setItemAnimator( new DefaultItemAnimator());
mRecyclerView1.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
mRecyclerView1.setAdapter(mAdapter);





prepareData();
}

private void prepareData() {
ContactPOJO contact = null;
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);

contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);
contact = new ContactPOJO("Dhruvam","9467884671","22/12/1995");
mArrayList.add(contact);

mAdapter.notifyDataSetChanged();
}



}

Also, do not dwell upon the notifyDataSetChange Method.

Step 7: Handle activiy_main.xml

The app is almost finished. Just add the RecyclerView Widget in the XML File and we’re good to go.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="dell.recylerviewpart1.MainActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>



</android.support.constraint.ConstraintLayout>

You’re done with the XML too.
If you run the app now, it should look like this.

Wohoo!

So we’re done with the application. But. There are still some things left. I’ll probably cover that in the next section: RecyclerView Implementation. Part — 3.2.

--

--

Dhruvam Sharma
AndroidPub

Google-certified Android Developer @Unikon. Android Geek. In love with Flutter. Blockchain Explorer. Dancer. 🕺 Reader. Coffee Addict. 😍