Don’t write RecyclerView adapters

…and don’t write ViewHolders

Miguel Ángel Moreno
4 min readNov 13, 2016

Almost every single app needs to show some collection of elements on the screen. In Android, the most efficient way to do it is using RecyclerView, a widget that can handle how the views representing those items are displayed on the screen. RecyclerView uses an adapter that tells which element from the collection is going to be shown on the screen at a certain position, which view is going to use and which views can be recycled. Creating new views is a very expensive operation in Android and that’s the reason why we use ViewHolders. They allow us to recycle the views going outside the screen when we scroll and reuse them for the items that become visible again.

The ideas behind RecyclerView are simple and effective, but there’s one problem: you need to write an adapter for every collection of items you want to show, and a ViewHolder for every type of item your list can show.

Unless you’re trying to do something more complex like sticky headers or expandable views, the process of writing adapters and ViewHolders is going to be very repetitive. You need to implement methods like getItemCount() returning the number of elements in your collection. Isn’t it obvious that it should be the size of the collection? Usually, the only interesting thing is the way one item is bound to a ViewHolder and thus to its view. And actually, it isn’t so interesting: it probably only sets some strings into TextViews, uses URLs to load images into ImageViews and so on… Exactly the kind of things the Data Binding library does directly in the layout XML.

So why end up writing a whole new adapter every time you want to show a collection of items? Wouldn’t it be cool to simply specify the list of elements you want to show, which item type will be represented by which layout and then use Data Binding to bind every item to its view? Well, that’s what I think and that’s why I’ve made a library that avoids me having to write adapters over and over again.

I introduce you LastAdapter. And I’d like to show you how easy to use it is:

That’s it! Pretty straightforward, right?

The first parameter is the list of items you want to show. Again, we can simplify things even more here. When your list changes, you need to notify the adapter about those changes to update the views. With LastAdapter, you can use an ObservableList and forget about notifying the adapter.

The second parameter is a resource value automatically generated by Data Binding (BR ≈ Binding Resources) and represents the variable you use in the layout:

For simplicity, you have to use the same variable name for all the item types within the same RecyclerView. So I recomend you always using BR.item and variable name=”item”.

Then you just “map” classes to the layouts they will use.

That was the most common scenario, but you may need to use different layouts depending on other criteria like the internal status of the item or its position in the collection. You can do that too:

The LayoutHandler interface allows you to use different item view types based on other criteria.

Stable IDs

It is recommended to use stable identifiers to improve the performance of your RecyclerView. To enable it, a third parameter can be passed to the constructor indicating whether you want to use stable IDs or not. Also, your item classes must now implement the StableId interface and override its single method returning the unique identifier for the element.

Callbacks & Listeners

Let’s continue with more features. Right now, you can use Data Binding to set click listeners right on the layout XML and call a method in the item class to handle it. But, if you don’t want to do it that way or there’s any operation that cannot be done through Data Binding, you can create your own ItemType and do it in your own way:

To create an ItemType, you need to provide the layout this item is going to use and a binding class that is automatically generated by the Data Binding library for every layout that uses it. Their names always follow the same pattern. Here, R.layout.item_book generates ItemBookBinding the same way R.layout.item_tweet_favorited would generate ItemTweetFavoritedBinding.

Now, you can manually set your click listeners or do any other operation in the onCreate method. Also, you can override the onRecycle method if you need to.

The binding parameter has methods that give you access to the item and to every view in the layout that has been given an id, so you don’t have to call findViewById if you need access to any view.

And again, here is another way to decide which ItemType should be used rather than just the class of the item:

Conclusion

There’s no need to waste your time writing adapters and ViewHolders unless you are trying to do something truly unique!

Thank you for reading, I hope you enjoyed my first post at Medium and, hopefully, I can return your time back to you by using the library ;)

https://github.com/nitrico/LastAdapter

By the way, I’m looking for a job!

Bonus: Kotlin!

Even though the library is written in Kotlin, you’ve seen that you can use it in your Java projects. However, if you are currently using Kotlin, you can do it even easier.

Basic usage in Kotlin
LayoutHandler in Kotlin
Use Type instead of ItemType to create types and callbacks easily in Kotlin, including onClick and onLongClick ;)
TypeHandler in Kotlin

--

--