A RecyclerView With Multiple View Type

Gilbert Christopher
7 min readJun 27, 2018

--

A guide to recyclable multiple lists on Android

ListView dan RecyclerView are pretty common widget that has been used on Native Android development. Most of time ListView and RecyclerView are used to show uniform item view, such as a simple text, icon and text, and so on. It’s meant to handle repeated structure in consistent content. But, to show a list of inconsistent content with various view types, it can be a different story. Unfortunately, there are still developers who do not know how to create an adapter to display some view type in the list properly.

Hi, My name is Gilbert Christopher. I am a Software Engineer who works for Moka. In this article, I want to share how to implement an Adapter to display multiple item view.

List are the most convenient ways to show the data on small handled device like smartphone. There are two ways to display a list on native android development, that is listview and recyclerview.

ListView vs RecyclerView

ListView is a view which groups several items and display them in vertical scrollable list. ListView has been around since the first Android 1.0. It was available even in API level 1. The usage of the ListView is actually really simple. In order to enable ListView, it’s just use the adapter component which provided by the application itself and create and populate the item view corresponds to particular position in the list. And over time, Android Developers continued adding more and more features to ListView in order to improve the performance and efficiency. For example, ListView could handle if there are tons of items since creating view is expensive and memory is limited. ListView recommends (not mandatory) to use ViewHolder pattern that a developer can use to increase the speed at which their ListView renders data. With ViewHolder pattern, convertView isn’t always be null and call findViewByID() only once at the first time when it assigned to the ViewHolder and that makes our smooth ListView scrolling. But, there are still missing on ListView. For example, if ListView are need to change into GridView, developer must rewriting a whole lot of core code that ListView used to do on this adapter. However, the really big problem of ListView is it really difficult to make ItemAnimator because that adapters don’t tell us enough to do them smart. When developers change an adapter, they can only call notifyDataSetChange() and recreate all of the views.

RecyclerView was introduced Android 5.0 (Lollipop) and it is compatible even with Android API Level 7. RecyclerView is an improvement over ListView. It works just like a ListView — displaying a set of data on the screen. But, RecyclerView as its name “recycles views” once get out of screen with the help of reuse pattern since ViewHolder pattern is mandatory. Anyways, RecyclerView offer some improvements over the ListView. These are the enhancement of RecyclerView:

  • LayoutManager : RecyclerView can put a list items easily at run time in the different containers (linearLayout, gridLayout).
  • ViewHolder : RecyclerView adapter forces developers to use the ViewHolder pattern which no need to call findViewById() each time for the entire dataset and on each bind view.
  • Notifying Adapter : Not only notifyDataSetChange(), RecyclerView support notifyItemInserted(), notifyItemRangeChanged(), notifyItemRemoved and much more to know what is actually happening on the items.
  • Item Animator & Item Decoration : Using RecyclerView.ItemAnimator & RecyclerView.ItemDecorator, developers can dynamically decorating and animating the views.

Using RecyclerView is a better as it reuses cells while scrolling up/down, animate common list action, decouples list from its container.

Motivation

RecyclerView is much more powerful, flexible and a major improvement over ListView. Many developers are always use this on native android development to show a list of data. However, even RecyclerView is very useful and support a multiple item view type, there are still a lot of Android developers who don’t know how to implement an adapter with multiple item view type in a proper way.

Previously, when I had to implement a feature which contains multiple item view type by using RecyclerView, I’m usually create an adapter with only one ViewHolder class.

The code snippet will be like this:

The adapter contains the bind of view, business logic, and much more. Assume we have a many types of items that we need to insert into our adapter. Since we have different types of items, we’ll bind all the views on single view holder, put all the business logic onBindViewHolder() method and use an if else statement to specify a block of code to be executed. All this was looks dirty and very difficult to change.

Finally, my senior Gilang Kusuma Jati at Moka gave me a suggestion how to implement an adapter for RecyclerView with different approach and today I want to share how to implement it to make the code cleaner, easy to understand and maintainable. The idea is use the concept of polymorphism to bind the view and business logic and I think that’s an elegant solution, that might be interesting for other developers facing a similar use case.

Implementation

I will use a project called Popular Movies, a sample project that I submit when I took a preparation course Associate Android Fast Track to get certified as Android Developer. The Adapter contains many kind of item type, such as String, Trailer object and Review object. You can find the repository on my github. The code below will be use two programming language, kotlin and java since Android Studio support both of them.

  1. BaseViewHolder

The first implementation is creating an abstract class called BaseViewHolder as a parent class. The class is a generic class which type parameter will provide a way to reuse the same code with different inputs. So, type parameter will be replaced by type arguments when the generic type is instantiated. In addition, making a parameter of generics, we can reducing the number of casts in your program which make the code better clarity and reducing of potential bugs.

BaseViewHolder extends RecyclerView.ViewHolder object to describes and provides access to all the views within each item row. The class contains one abstract method named bind() since the method needs to be overridden in child class. The parameter type for the abstract method bind() named item will follow the type given on the class BaseViewHolder. The implementation will be like this:

2. SubClasses of BaseViewHolder

After BaseViewHolder is created, the next steps is creating a subclass ViewHolder based on item type. Because the items consist of 3 types (String, Trailer, and Review), the code will also create 3 ViewHolder class namely TitleViewHolder, TrailerViewHolder, and ReviewViewHolder. Each class must be extends BaseViewHolder since BaseViewHolder extends RecyclerView.ViewHolder object to describes the views within each item row and must be override the abstract method from BaseViewHolder, bind() to fill the business logic for each item. The implementation will be like this:

With the separation of the classes, developers are easier to understand the code than combine them into one class ViewHolder. In addition, the codes are easier to maintain if other developers want to add or change the code in the future.

3. Adapter Class

After BaseViewHolder and ViewHolder classes has implemented, the last step is implement the adapter class which extends the abstract class, RecyclerView.Adapter. Because of RecyclerView.Adapter is abstract class, we as developer need to define all the abstract method and some method that we needs to implement the adapter class. For this project, we need to define:

  • getItemViewType(position: Int)

This method is going to return the view type of the item at position for the purposes of view recycling. Before we implement this method, we should be create a static variable or companion object for kotlin because the view type using id resources to uniquely identify item view types. The code will be like this.

If the data wasn’t String, Trailer, or Review, it would be throw one of RuntimeException, that’s an IllegalArgumentException to make the code fail fast. Throwing an IllegalArgumentException is a way for the program to protect itself from an illegal or inappropriate argument.

  • getItemCount()

getItemCount() will be called to know the size of the list. It generally return the total number of items in the data set held by the adapter.

  • onCreateViewHolder(parent: ViewGroup, viewType: Int)

In onCreateViewHolder, we will inflate the view that we will be using to hold each list item. This method will be called when RecyclerView needs a new ViewHolder of the given type to represent. The params are the Viewgroup parent and int viewType. Parent is the ViewGroup into which the new View will be added after it is bound to an adapter position and viewType is the type of the new View. This method will return a new ViewHolder that holds a View of the given view type.

  • onBindViewHolder(holder: BaseViewHolder<*>, position: Int)

This method will be called by RecyclerView to display the item at the given position into ViewHolder. The params are BaseViewHolder holder and int position. In kotlin, the holder on BaseViewHolder use star projection(<*>) which mean we just want to use the type argument in a safe ways without caring about the spesific type of the value. Holder is the ViewHolder which should be updated to represent the contents of the item at the given position in the data set. Since ViewHolder has separated into 3 classed and each class is defined the logic on bind() method, we don’t need put all the business logic onBindViewHolder() method. We just need to call bind() method from BaseViewHolder object. The code will be like this.

This way is very useful. So, we can have different view holders for different data types, using different layouts.

Fully implementation of my adapter looks like this:

  • Kotlin:
  • Java

Conclusion

The concept of polymorphism is really useful to implement multiple item view type on the adapter. By separating ViewHolder class based on view type, it would make the code looks cleaner and easier to read. In addition, putting a business logic on bind() for each ViewHolder class, that’s also an elegant solution. It would make the code are easier to change for the future rather than put all of the logic at onBindViewHolder. By now this implementation will perform for the next implementation at Moka projects.

If you enjoyed this story, please click the 👏 button and share to help others find it! Feel free to leave a comment below.

--

--