Adapter for RecyclerView

Adapter for RecyclerView

Introduction

RecyclerView

The adapter is a bridge between the data source (Array object, List object…) and the user interface. The role of the adapter object (implements the Adapter interface) is to read data from various data sources, and based on them fills View objects with members of a ViewGroup.
So far we have used ListView, but the recommendation is to use RecyclerView instead of listView, especially whenever you have data collections whose elements change during application execution in response to user activity or network events. RecyclerView is the successor of ListView and GridView, and is intended to efficiently render adapter-based views.
RecyclerView has its own adapter “RecyclerView.adapter” which implements the ViewHolder pattern, integrates “convertView” and has built-in methods that replace everything we did with “CustomArrayAdapter” and improves the efficiency of the display when scrolling the list.

RecyclerView.Adapter creation procedure

a) List data

In this example, one member of the list accepts more data, therefore it is necessary to create a class that will be a “model” for creating objects that store the data of one member of an AdapterView:

We have defined that through the constructor data is inserted for each member of the list, and therefore we can generate an initial list of data within the Activity (Fragment):

b) Creating an AdapterView

It is necessary to define the place where the data list will be placed as part of the Activity (fragment) layout. This part is similar to a regular adapter, once it is created it uses a RecyclerView instead of a ListView.

c) Creating a custom layout for one list element

custom-adapter-row

Now it is necessary to create a custom layout, which will display multiple data unchanged for one element of the list. This part was not needed with the “regular” adapter, but now it is needed due to excess data, because we cannot use already predefined android layouts that accept only one data. In this example, we have three pieces of data for each row: an image and two texts.

NOTE:
Clicking on the row element of the RecyclerView does not produce the expected “ripple” effect. In order to activate such an effect, it is necessary to add an attribute to the root View of the row layout: android:background=”?android:attr/selectableItemBackground”

See the full sample code here.

d) Creating a Custom Adapter class

To create a customAdapter class, it is necessary that our class extends the RecyclerView.Adapter class. In order to define what type the data in the adapter is, we first need to create an internal static ViewHolder class inside the adapter that extends the RecyclerView.ViewHolder class. When we created a static ViewHolder, we need to define its own constructor method inside it.

Now we can insert the name of our ViewHolder andthus we define which type the adapter accepts.

Only after this we can implement all the methods required by the RecyclerView.Adapter class, and define a constructor that accepts an ArrayList of data as a parameter. After all, the class should look like this:

Now that we have created the skeleton, we need to define the details.

Defining the ViewHolder class

First of all, we need to target all sub elements from the example_item.XML layout within the ViewHolder class:

Creating a ViewHolder instance

First, we need to parse the row layout into a View object, and this is done within the onCreateViewHolder() method, and then that object is passed as a parameter to the constructor of the new ViewHolder instance:

Inserting data into the list is done as part of the onBindViewHolder() method:

Defining list size

The size of the list is defined in getItemCount()

The entire Custom Adapter class now looks like this.

e) Inserting a RecyclerView into an Activity

The necessary things that define a RecyclerView are:

  • View representing RecylerView
  • RecyclerView.LayoutManager used to define the layout of elements within the RecyclerView (LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager)
  • Adapter used to populate the RecyclerView

NOTE:
RecyclerView is generally defined so that it does not depend on child elements, but mainly on the parent View in which it is placed, so its height and width generally do not change over time. But we have to emphasize this information so that Android would not check it every time when we insert a new or remove an existing element. For this reason, to improve the efficiency of the RecyclerView it is good to define our RecyclerView as having a fixed size with setHasFixedSize(true).

First of all, we need to define the fields that will later be available to other parts of the code:

In the onCreate() method we will set the created fields:

You can view the entire code contained in the Activity here.

NOTE
If we add or remove an element from the RecyclerView, after each addition it is necessary to notify the system that a change has occurred by calling the method notifyItemInserted(position):

Also, after each removal of an existing element, the system should be notified that a change has occurred by calling the method notifyItemRemoved(position):

So the methods for inserting and removing elements would look like this:

See all methods that can be used to notify the system about changes here.

f) Defining the click listener

Along with the standard ListView comes the onItemClick interface, however, it is not there with the RecyclerView, so we have to create our own interface and customClickListener (see how customListeners are created here).

Creating a new interface

First, we need to define a new interface and a callback method within our Custom Adapter:

Setter method

And then we need to define the field and the setter method, by calling which in Activities we define the object that listens to the event:

Triggering events

It is necessary to “trigger” the event by clicking on some element of the RecyclerView list that is defined in the ViewHolder class, and we will do this by calling the callback method of our interface:

We will call this method when the “itemView” element is clicked (represented as a constructor method parameter). For this reason, the method call will be placed within the onClick() method:

You must have noticed that android studio reports an error that it cannot find the listener variable since our class is static. To make this variable available, we’ll pass it as a parameter to the constructor function of the Custom ViewHolder class. Inserting a listener as a class parameter is the easiest to achieve if you mark the listener that is the problem in AndroidStudio and call the help menu with ALT + ENTER, where the option “Create parameter listener” is selected, after which Android Studio will do everything by itself.
So the whole ViewHolder class would now look like this

NOTE:
Every time you click on an element of the list, we need to know which element was clicked, this is simply obtained using the method getAdapterPosition()

Defining the object that listens and the contents of the callback method

Within the Activity there is an object that implements the interface, which in our case is an instance of the “mAdapter” adapter itself. Then that object calls the setter method setOnItemClickListener() to define the object that listens to the event through the passed parameter. In our case it will be an anonymous object that implements the interface “on the fly”. We will define the action that should be performed after triggering the event by “overriding” its callback method onItemClick:

See the full code of Activity here.

This is the simpler way and everything is defined within the adapter class. First, our ViewHolder class needs to implement View.OnClickListener:

And after that, AndroidStudio will report an error and require its callback method onClick() to be implemented as well. Within this method, the action that takes place when the event is triggered is defined, i.e. when a member of the list is clicked.

In order to define a listening object, we need to pass it as a parameter to the setOnClickListener() method in the ViewHolder constructor. In our case it’s the ViewHolder itself so we’ll pass “this”:

So the entire ViewHolder would look like this:

×

×

×

×

×

Method Description notifyItemChanged(int pos) Notify that item at position has changed. notifyItemInserted(int pos) Notify that item reflected at position has been newly inserted. notifyItemRemoved(int pos) Notify that items previously located at position have been removed from the data set. notifyDataSetChanged() Notify that the dataset has changed. Use only as a last resort.