Combine your lists with MergeAdapter

Prafull Mishra
4 min readApr 4, 2020

Say bye-bye to view types 👋

combine adapters with MergeAdapter
^ by me, inspiration from Android Developers

Dynamic list-based UI is all the new rage. You know what it means — ViewTypes! One for each type of view. Its all bells and whistles when working on a small project, but what about a production app with a dozen services and item animations? In these cases, managing multiple view types for a RecyclerView can quickly get out of hands. So complex that Airbnb even built an entire architecture for this use-case.

However, there still lies a grey-area, where your app is not that small, neither too-big. Or probably you just don’t want to rely on a different architecture altogether. Luckily, Android developers thought of this.

Here comes MergeAdapter

With the latest release of RecyclerViewrecyclerview:1.2.0-alpha02, there is a new class available named MergeAdapter. It enables sequential merging of multiple adapters, before setting it to a single RecyclerView. This eases the pain of showing different layouts together, without the need of maintaining any view types. All the logic related to different types of layout can be kept separate in different adapters, thereby helping us to keep our code and logic well organized and encapsulated.

Let’s see it in action:

MergeAdapter implementation

As you can see, we first created two adapter individually, then we added them both to an instance of MergeAdapter, and then finally passed this instance to the RecyclerView.

Kind of reminds me of MediatorLiveData 🤷‍♂️

The result which can be obtained from these few lines of code? Here you go:

Merged Adapter in action! Also, Hela is the coolest villain of MCU 🤪

Isn’t it amazing!

If you think about it, this can be helpful in many cases. From having a header and footer maintained separately, to showing loaders and other unique layouts in a sequential manner, all without bloating the adapter responsible for showing the actual data in between.

Note that, this merge is sequential. Which essentially means when list of one type ends, after that only list of another type can be shown.

Minor details

If you have had a good-enough experience with RecyclerView, I know this “merging-adapter thingy” would only raise-more concerns for you, which may include but not limited to :

  • And what about updating data with this adapter?
  • What happens to ViewHolder?
  • Does it changes the way we get position of a list item?
  • Will we get overall position or list-wise position?

Let’s try to find answers! 🧐

Updating list items

Since multiple adapters merge to form a merged adapter, issuing notify calls on any of the constituent adapters will trigger computation by the MergeAdapter as well, which will then finally dispatch required updates to the RecyclerView. It is recommended to dispatch updates in a more confined manner, rather than using notifyDataSetChanged, which will trigger reloading of entire content of the RecyclerView.

MergeAdapter won’t map notifyDataSetChanged to any other notify calls.

ViewHolders

Each adapter will work with its own pool of ViewHolders. Which means, if you combine multiple lists, their ViewHolders will not spill over to the adjacent adapters. However, there may be case when adjacent adapters inflate the exact same layout for their list items, in which case it will be efficient to let them share their pool of ViewHolders. To enable this, we need to pass in a MergeAdapter.Config object with isolateViewTypes = false, while constructing the MergeAdapter .

While in the previous example, we saw the construction of MergeAdapter, and the following adapter addition as:

val mergedAdapter = MergeAdapter()                               mergedAdapter.addAdapter(firstAdapter)                               mergedAdapter.addAdapter(secondAdapter)

to include a configuration, this will change to:

val configBuilder = MergeAdapter.Config.Builder()
configBuilder.setIsolateViewTypes(false)
val config = configBuilder.build()
val mergedAdapter = MergeAdapter(config,firstAdapter,secondAdapter)

Using MergeAdapter.Config, we can also change the stableIdMode to one of NO_STABLE_IDS , ISOLATED_STABLE_IDS and SHARED_STABLE_IDS. For more info on stableIdMode check out this link.

Getting ViewHolder positions

In a simple adapter we use ViewHolder.getAdapterPosition() to get the position of the current list item. Since MergeAdapter combines various adapters, to achieve the same use ViewHolder.getBindingAdapterPosition(). But keep in mind, that this will return the position with respect to the adapter it is in, and not the whole MergeAdapter .

getting viewholder positions wrt. adapter

To get the position with respect to the MergeAdapter, use ViewHolder.getAbsoluteAdapterPosition() instead.

For a complete implementation, have a look at the code in my sample project on MergeAdapter (of which these screenshots are) on Github :

This ends our hands-on with the wonderful new MergeAdapter.

Clap if you too feel thankful to Android developers for giving us this awesome piece of code! 👏

--

--