Lists with RecyclerView

Rafa Araujo
11 min readJan 23, 2017

--

Versão em português aqui

It is very common for applications to have lists to display their content efficiently. And if not well implemented by the developer can bring displeasure to the user, its final client. Thinking about it Android gave us a powerful component called RecyclerView.

About RecyclerView

Tell your boss that you will now recycle views

RecyclerView is an “evolution” of ListView and GridView, components present since the first version of Android to make lists and grids of content.

The major benefits are:

  • Updates (improvements, new features, fixes and etc)
    The RecyclerView is frequently updated independent of the version of Android, because it is part of the Support Library v7 and has received great attention from Google’s developers since its launch, focused on constant adjustments to continually improve performance. The ListView and the GridView are present inside the Android SDK. So there are only updates to these components when the Android version is updated, which is not as frequent as the Support Library v7.
  • Performance! View reuse when user scroll the list
    As the name of the component suggests, when the user scrolls, the component identifies the views that are no longer visible to the user and reuses them by placing new values according to the content of that position in the list. Doing this prevents you from creating new views for each new content.
    This design-patterns is called Object Pool where the goal is to reduce the time and cost of instantiations, reuse objects, improve performance and control over resources. Another design-patterns used is the View Holder that aims to keep the references of the view helping to recycle. So it is not necessary to look up the references of the view every time it is necessary to present a new view for the user.
    Many developers have already applied these concepts to the ListView, but in RecyclerView it is mandatory and easy to use, always focus on for better performance.
  • Animation
    The RecyclerView by default uses the DefaultItemAnimator, class that animates the contents of the list when they are added, removed or changed their position, giving better feedback to the user. The developer can also define his own animation if he wishes.
    In ListView and GridView the animation should always be implemented if the developer desired, starting from zero.
  • Layout manager
    In RecyclerView there is a “layout manager” that defines what will be the position of the items in the list (whether it will be a horizontal list, vertical list, a grid and so on). With this flexibility we can change the layout of the items according to the user’s configuration without having to recreate the entire RecyclerView structure at run time.
    The ListView only supports vertical list, and if the user wanted to change the layout of the items to a grid the developer would have to create a GridView and handle the necessary adjustments again.
  • Updating only necessary items
    In ListView when it was necessary to update the list because an item was inserted, modified or removed the API only allowed to update the complete list or a lot of code was needed to update only the desired content. In RecyclerView the API is optimized for this scenario and predicts this focused on improving performance and provides the means to update only the content that is necessary.

Components in RecyclerView

Structure of a list

RecyclerView is just the ViewGroup where it will contain the list, to use it you will need a few more components. Here is a brief description below:

  • RecyclerView
    Visual component that will be in the Activity/Fragment and will position the list on the user’s screen, as well as a text field or button, for example.
  • LayoutManager
    It is the content manager described above. In it is defined what is the layout of the list items (whether it will be a vertical or horizontal list, for example).
  • Adapter
    Class responsible for associating the list of content/objects with the corresponding view. Where each object in the list will become an item in the list. This is also where you define whether an item should be displayed or not.
  • ViewHolder
    It is the reference to the view that is the visual part of each list item, which will be replicated to all elements (In the structure above, it would be inside the Adapter)

Talking is easy, show me the code

Show me the code or it did not happen

To use RecyclerView it is necessary to place the dependency in the build.gradle file of the application module (usually what is inside the app folder).

Using the 25.1.0 version of RecyclerView, CardView and Design library.

CardView and Design libraries are not required for list building, but are being used in the examples

Version 25.1.0 is being used (most current at the time this article was written) because it is the version corresponding to compileSdkVersion. Always give preference to the most up-to-date version if possible.

That Done, the next step is to create the lists.

Regular List

Vertical list

The first step is to put RecyclerView in our Activity layout.

Main layout where the list will be.

Besides the RecyclerView the screen will have a button to include the content, in this case the FloatingActionButton. The rest of the layout is the same as any other, with no secrets.

An interesting attribute of the lists on Android is tools:listitem that was placed in the above RecyclerView component.
When placed with the ViewHolder layout (in the example is @layout/main_line_view), we can see in the Preview of the layout editor of Android Studio how our list will look, just put your layout.

Preview list in Android Studio

Also is need to do the layout of the ViewHolder, which will be the layout that will be used on each of the lines.

Layout corresponding to each line

Now it’s time to set up our Activity.

Activity where the list will be.

In addition to binding the components of the view as usual (doing findViewById(), for example) it’s needed to configure the LayoutManager and Adapter.

An extra setting added is the addItemDecoration that receives a DividerItemDecoration, using the VERTICAL parameter. This adds dividing lines between the items in the list.

In this example, the LinearLayoutManager was chosen as LayoutManager. This type configures the list as a simple and vertical list.

Much has been said about LayoutManager, but this class is just an abstraction. What we should use are the abstract classes, which will be presented according to each example.

Another component that should be created is the ViewHolder. Your layout has already been created above so you need to create the Java class to bind the fields, as we do in an Activity to be able to access the visual components.

ViewHolder that will bind Layout visual components to Java code.

In the example, the Adapter is receiving in the constructor the list of objects, which in this case is UserModel. It is on this list of objects that the visual list is constructed.

Adapter from our simple list.

For the class to be an Adapter it is necessary to extend RecyclerView.Adapter<ViewHolder> and implement the required methods::

  • onCreateViewHolder(ViewGroup parent, int viewType)
    Method that should return layout created by the already inflated ViewHolder in a view.
  • onBindViewHolder(ViewHolder holder, int position)
    The method that receives the ViewHolder and the position of the list. Here you retrieve the object from the list of Objects by position and associated with the ViewHolder. It’s where magic happens!
  • getItemCount()
    Method that should return how many items there are in the list. It is advised to check if the list is not null as in the example, because when trying to recover the amount of the null list can generate a runtime exception(NullPointerException).

It is noteworthy that the onCreateViewHolder and onBindViewHolder methods are not called for all items initially, they are called only for the items visible to the user. When the user scroll the list these two methods are called again by associating the recycled view with the content of that position that will now be visible.

Done that and it’s ready. We have a list!

So you’re telling me… We have a list passing an empty list on the Adapter

We have a list, in fact. But when it was created in Activity, an empty list was passed on the adapter. Now it’s time to popular, edit and remove items.

Keep in mind that Adapter will swap content from views that will be recycled through this list of objects. Therefore, to add, update or remove items from the list we must work with the list of objects that was passed in the constructor and is inside the Adapter class (List<UserModel> mUsers). Your Adapter should be able to take care of this recycling.

This article will not cover codes that are not related to RecyclerView. For example, third-party libraries and techniques that helped in developing the code.

As described in the presentation will use a button to generate content. Clicking this button calls a public Adapter method to add new items to the list.

Insert objects in the list and update the Adapter

Add a new item to the list and notify that there are changes.

When the user clicks the add button will be passed by parameter the new Object (UserModel).
This new object will be added in the original Adapter list (line 11) and then it is necessary to “notify” the adapter that there is a new item in that position (line 12).

As mentioned above, this is one of the great advantages of RecyclerView where it is updated only the new list item, rather than updating the entire list to notify that there is a new view, as it was done in the ListView.

Inserting items in the list.

In this example, two buttons have been added in each view. One to increment the number of each item in the list and another to remove that item from the list.
The click actions of these buttons have been configured in the onBindViewHolder method of the Adapter, as shown in the Adapter above.

Update objects in the list and update the Adapter

Editing an object from the list and being notified that there are changes

The code for updating an item is much like the code to include an item. Just locate the object in the Adapter mUsers list and update as you wish. After this, it is necessary to notify the Adapter again that there is an update on the item from the indicated position (line 4).

Updating items in the list

Remove objects from the list and update the Adapter

Removing an item from the list.

To delete an item from the list it is necessary to remove it from the list of objects in the class (line 3, removing from the mUsers) and notify the Adapter that item has been removed (line 4).
In addition, it is necessary to notify the items below that there are changes with them (line 5), because when removing an object from the list it is necessary to warn Adapter that the objects below it have changed their index. Otherwise, the following scenario may occur:
Imagine that a list has 5 items and the user has removed the second. When the user clicks on the “new” second item (which was the third) it will actually interact with the third item. That’s because the removed item has disappeared and Android has animated the scrolling of the items below, but only visually. It is therefore important to always notify the Adapter that these below items have changed their position.

Deleting items from the list

Horizontal list

Items aligned laterally, where it slides left and right

In RecyclerView it is very easy to change from a vertical list to a horizontal list, simply adjust the LayoutManager in Activity.

Configuring LayoutManager for horizontal list

The LinearLayoutManager is also used, but with another constructor passing the context, the HORIZONTAL configuration and a boolean defining whether the list will display the items in reverse order or not.

If you want a vertical list with the items in reverse order we must use the same constructor, but passing VERTICAL in the second argument.

Example of horizontal list

Another component that may need to be updated is the ViewHolder layout, so that the view is best adjusted in the horizontal list. In the vertical list example, a line with text and two buttons was used. For the horizontal list example, the CardView component and one text component in the center are being used for better visualization.

In addition to the Adapter’s onBindViewHolder method that has been changed to associate one more field (Latin green text in the center of the view), the other Adapter settings and also the insert, change, and delete functions are exactly the same. And with few changes we have a new provision of content.

One dream, one soul, one prize, one goal… 🎤

Grid

Grid Content

Again, the previous structure is used by changing only the LayoutManager.

Configuring ReciclerView to use grids with 2 columns

For the layout of the grid type, the GridLayoutManager implementation of the layout manager was used. In the constructor was passed the context and the desired number of columns in the grid.

Grid list example

The implementation of Activity, Adapter, ViewHolder… you already know, there are no differences.

Can you feel the “magic”?

However, sometimes the content/layout is not of a fixed size for each CardView, and the grid may have gaps and not make the most of the user’s screen. For example in the image below:

Grid with gaps between views

For cases like these Android has a specific manager. And we go to him:).

Scalable grid

With the StaggeredGridLayoutManager the content grid gets scalable and Android will take advantage of the end of each card from each column to start the next view.

Using scalable grid

With this small change, Android takes more advantage of the user’s screen to view more content!

Scalable grid displaying the maximum content on the screen

Tips and good practices

Take note here!
  • Keep in mind that you should always work on the object list and the Adapter should be able to handle the changes. The list will scroll and the Adapter should be able to work the data by it self. It makes no sense to try to access the list views through places other than the Adapter.
  • Separate the responsibilities of interface and data loading. Do not load data into the main thread as this may freeze the application for some time, disappoint the user.
  • If the contents of the list are simple and without actions it is not appropriate to use CardViews. According to Google’s design reference, this can distract the user. You can find CardView reference here and list here.
  • If the application uses multiple lists and they are similar, consider using the same Adapter and ViewHolder if possible, avoiding duplicate codes.
  • Consider the use of RecyclerView. As we have seen, it is not so simple to create a structure for RecyclerView. If you need a very simple list, with no clicks and whit no interactions, consider ListView. Although an outdated component is not yet deprecated.

Final thoughts

Sample Code

The code used in the post is this GitHub repository.

Official documentation

In the Android documentation there is a part talking about RecyclerView, you will find in this link. The documentation is at this link.

Contacts

Find me at orafaaraujo@gmail.com or on skype orafaaraujo, and on slack/medium/twitter @orafaaraujo.
Feedback are welcome!

Android Community on Brazil

Join the largest forum on Android in Brazil slack Android Dev BR.
Site: http://www.androiddevbr.org | Invite: http://slack.androiddevbr.org

Thank you!

--

--