
Playing with the new MergeAdapter on Android
Mobile apps have come a long way in terms of offering a rich user experience and have found new ways of structuring and surfacing information in the limited real-estate of a phone screen. Every app these days has some implementation of a “feed” of sorts that users interact with to consume the app’s content.
On Android, the de-facto way of implementing a feed/scrollable list of content is a RecyclerView. But as the UI for most apps has become more sophisticated, implementing a complex list containing multiple item types is no longer straightforward without falling back on third-party libraries like Epoxy.
To make handling multiple feed item types whilst still maintaining clean abstractions between them in code, Google recently announced MergeAdapter, a new class available in RecyclerView version 1.2.0-alpha02 onwards. MergeAdapter reduces the friction when you want to “merge” multiple adapters “sequentially” within a RecyclerView.
In this short post, we will take a look at how to implement a screen containing a RecyclerView with a fixed header item on top. This UI pattern is quite common in situations where you want to give the user additional context about the information or surface certain unexplored features in the app in a non-intrusive manner as shown below.

The screen we will be implementing is pretty straightforward, it shows members of the mobile team at Buffer along with a helpful header as the first item as shown below.
You can download the code for the project here

The header card item is dismissible. Let’s get started building this 🙌
Dependency
In order to use the MergeAdapter class, you need to ensure you are using the correct RecyclerView dependency. It’s available starting version 1.2.0-alpha02. Open your app level build.gradle file and append the following to your dependencies list
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha03'
Setup
The screen is divided into two distinct visual element types which will use their own independent adapters
- The header card which is represented by the WhatsNewAdapter class in code
- The teammate card which is represented by the BufferooAdapter class in code.
There’s nothing out of the ordinary going on in the BufferooAdapter so I won’t cover it here, you can take a look at the code here.
The WhatsNewAdapter does have a few minor details that are worth looking at.
Instead of using a list of items like you may have used most of the time while using an Adapter, the WhatsNewAdapter uses a single object whatsNew.
- The hasWhatsNewData() method determines how many items the adapter will display, 1 or 0
- The getItemViewType() returns the resourceID of the header layout item. This is to ensure that if we want to reuse a certain ViewHolder, the same view type isn’t pointing to different ViewHolders. This is more of a best practice to ensure each view type returns a unique identifier.
Let’s hop over to the MainActivity where we are wiring everything together
We’re doing a few things in the MainActivity.
- The initRecyclerView() method instantiates the individual adapters in the normal way and then creates a MergeAdapter instance, passes the two individual adapters, and assigns it to the RecyclerView’s adapter property.
- It’s worth noting that the order in which you pass the individual adapter instances to the MergeAdapter constructor is the order in which they will be rendered, i.e. the header will be shown first followed by the list of teammates
- The onDismiss() method which is invoked on clicking the Dismiss text on the header, assigns null to the whatsNew object in adapter for the header and calls the notifyItemRemoved method to let the adapter change the list UI accordingly.
This was pretty much it. For most conventional use cases this is all you need to do to set up and take advantage of MergeAdapter.
But at this point, you may be wondering.
Why go through the hassle of using MergeAdapter? There are other ways to build this UI.
You are absolutely correct. This can be achieved in a variety of different ways.
- You could have a single RecyclerView with multiple ViewHolder types i.e. the Heterogeneous Layout approach.
- The header does not necessarily need to be a RecyclerView item, it can be a card with a GONE visibility attribute in the parent layout.
Both of these approaches are correct and doable but both have tradeoffs in terms of abstraction and flexibility.
In the case of having a single RecyclerView with multiple ViewHolders, we lose out on clean abstractions. Consider the scenario where you already have 5 different ViewHolder types in a RecyclerView and your PM reaches out to you asking you to implement a promotional card item that will be on the top of the list which will let users avail discount on your products.
It will definitely be a considerable effort accounting for a new item and it’s positioning in the list, not to mention accounting for the position change upon interaction. It will also unnecessarily introduce the header view type’s logic into the main adapter when it should ideally be isolated away.
You can imagine how quickly the class can get out of control orchestrating different view types.
In the second approach, if the parent Fragment/Activity is already fairly nested and complex with a lot of different things going on in it, adding yet another ViewGroup can get messy and you may unintentionally end up breaking a few things here and there.
By using MergeAdapter you are able to
- Abstract away the header’s functionality into its own file
- Retain a flat view hierarchy in the parent layout because you are able to use multiple adapters in the same RecyclerView.
Of course, MergeAdapter is not a silver bullet by any means, its best suited for situations where the view types and their positions are known/predetermined.
It also makes it easy to introduce change into one view type without necessarily affecting the others.
Pitfalls to avoid
There are a couple of key things to keep in mind while working with MergeAdapter
- Each adapter passed into the MergeAdapter constructor will maintain its own pool of ViewHolders. If you do however need to use the ViewHolders across multiple adapters you must reuse them. This can be done quite simply by using a MergeAdapter.Config object and setting the isolateViewTypes property to true
- Always prefer specific notify events over notifyDataSetChanged(). Specific notify events are efficient and prevent overdraw and also give you pretty animations out of the box. If you extend the ListAdapter class these will come for free but implementing DiffUtils callbacks is also fairly straightforward. Another reason to avoid using notifyDataSetChanged() is the way in which MergeAdapter behaves. If one of the adapters passed to the MergeAdapter calls notifyDataSetChanged the MergeAdapter will also end up calling notifyDataSetChanged(). So as a general rule of thumb, prefer granular updates over force redraws.
- If you used ViewHolder.getAdapterPosition() method in the past, to get the position of a ViewHolder item in the adapter, it will no longer work with the MergeAdapter as we’ve “merged” multiple adapters into one. Use ViewHolder.getBindingAdapterPosition()instead and if you are reusing ViewHolders across adapters, make use of ViewHolder.getBindingAdapter() to get the adapter that had last bound a particular ViewHolder.
Conclusion
That’s all folks! I hope you enjoyed this short post. Let me know if you have any questions in the comments below. You can find the code for the sample project here. Until next time!