Merge Multiple adapters with MergeAdapter

Android introduced the most awaited feature of merging the data adapter into the list with the release of recyclerview:1.2.0-alpha02 package.

MergeAdapter is a new class available which enables you to sequentially combine multiple adapters to be displayed in a single RecyclerView. This enables you to better management of your adapters rather than having to combine many data sources into a single adapter.

One use case for this is displaying a list loading state in a header or footer. For example, let’s say that we have the following 3 adapters:

 val headerAdapter: HeaderAdapter = …
 val contentAdapter: ContentAdapter = …
 val footerAdapter: FooterAdapter = …
 
 val mergeAdapter = MergeAdapter(headerAdapter, contentAdapter, footerAdapter)
 
 recyclerView.adapter = mergeAdapter

It will display the items sequentially from each adapter.

Having different adapters allows you to better separate the concerns of each sequential part of a list. For example, if you have list and wanted to add header & footer, you don’t need to put the content related to header & footer in the same adapter, rather you can encapsulate it in its own adapter.

MergeAdapter Properties

ViewHolders

By default, each adapter maintains their own pool of ViewHolder, with no re-use in between adapters. If multiple adapters display the same ViewHolder, you may want to reuse instances between them.

with a MergeAdapter.Config object, where isolateViewType = false you can achieve this. Like this, all the adapters merged will use the same view pool.

To support different ViewHolder types, you should implement Adapter.getItemViewType

class HeaderAdapter() : RecyclerView.Adapter<LoadingStateViewHolderHeaderViewHolder>() { 

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return LoadingStateViewHolder(parent)
   }

    override fun getItemViewType(position: Int): Int {
        return R.layout.item_header
    }
}

class FooterAdapter() : RecyclerView.Adapter<LoadingStateViewHolderFooterViewHolder>() { 

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return LoadingStateViewHolder(parent)
    }

    override fun getItemViewType(position: Int): Int {
	return R.layout.item_footer
    }
}

Data changes notifications

When an adapter part of a MergeAdapter calls one of the notify functions, the MergeAdapter computes the new item positions before updating the RecyclerView.

From the RecyclerView’s perspective, notifyItemRangeChanged means items are the same, just their contents changed. notifyDataSetChanged means there is no relation between before and after. Hence, we cannot map notifyDataSetChanged into notifyItemRangeChanged.

If an adapter calls Adapter.notifyDataSetChanged, MergeAdapter will also call Adapter.notifyDataSetChanged, rather than Adapter.notifyItemRangeChanged. As usual with RecyclerView avoid calling Adapter.notifyDataSetChanged, prefer more granular updates or use an Adapter implementation that does this automatically.

Finding ViewHolder position

You might have used ViewHolder.getAdapterPosition in the past to get the position of a ViewHolder in the adapter. Now, because we’re merging multiple adapters, use ViewHolder.getBindingAdapterPosition.

If you want to get the adapter that last bound a ViewHolder, in the case where you’re sharing ViewHolders, use ViewHolder.getBindingAdapter.

That’s all! If you want to sequentially show different types of data that would benefit from being encapsulated in their own adapters, start using MergeAdapter.

For a complete implementation, check out this link.

Happy Coding 😀 …..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.