ConcatAdapter takes multiple recycler view adapters and merges them together to show with single RecyclerView.
This article demonstrates on implementing ConcatAdapter in android application. I have created a useful example, to use this feature in your app. So Let’s get into it and you can check the video below what it looks like.
You have to change your RecyclerView dependency from v1.1.0 to v1.2.0-alpha04. This class comes with upgrading to newer dependency which is still in alpha release. You can check for new features and fixes available from official Android Developer Page.
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha04"
Note: As of alpha02 update, earlier this has renamed to ConcatAdapter from MergeAdapter.
1. Create ConcatAdapter
Implementing a RecyclerView with multiple Adapters using ConcatAdapter:
// Get reference to created RecyclerView layout.
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// First Adapter
AnimalAdapter animalAdapter = new AnimalAdapter(animalList);
// Second Adapter
PlanetAdapter planetAdapter = new PlanetAdapter(planetList);
// Create a new ConcatAdapter and pass created adapters in sequence we need to show.
ConcatAdapter concatAdapter = new ConcatAdapter(animalAdapter, planetAdapter);
// Attach adapter to recyclerView.
recyclerView.setAdapter(concatAdapter);
2. Removing a Adapter
You can remove any adapter from previously added to ConcatAdapter in runtime.
concatAdapter.removeAdapter(animalAdapter);
This could be helpful when there is no items in the list to display or depending on use-cases.
3. Adding a Adapter
Similarly you can add adapter to ConcatAdapter at run-time.
concatAdapter.addAdapter(animalAdapter);
Conflict between adapters
By this time you might be wondering if adapters share same ViewHolder or similar item id’s. But that is not how it works, If there are 2 number of adapters concatenated they both use different ViewHolders.
You might want to take look at below image which outlines the working.

Which means the item id’s between these adapters will be same and uses different list items to populate the data in adapter.
For example, If the first item inside AnimalAdapter and first item in PlanetAdapter are same, we still don’t face any conflict while working with those id’s. But you have to handle such operations if you they are making use of different models.
4. Passing data from RecyclerView
When you implement ConcatAdapter with RecyclerView you might end up with multiple ViewHolders, Models and List items. So while passing the data between other activities you have to aware of which data needs to be passed.
Assume we are passing data from MainActivity to DetailActivity using intents when user clicks a item in the list.
AnimalAdapter click listener:
Model = Animal.java , ViewHolder = AnimalViewHolder
@Override
public void onAnimalSelected(Animals animals) {
Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
intent.putExtra(DetailActivity.INTENT_EXTRA_ANIMAL_DATA, animals);
startActivity(intent);
}
PlanetAdapter click listener :
Model = Planet.java , ViewHolder = PlanetViewHolder
@Override
public void onPlanetSelected(Planets planets) {
Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
intent.putExtra(DetailActivity.INTENT_EXTRA_PLANET_DATA, planets);
startActivity(intent);
}
5. Receive data in DetailActivity
Intent intent = getIntent();
if (intent != null) {
if (intent.hasExtra(INTENT_EXTRA_ANIMAL_DATA)) {
final Animals animals = intent.getParcelableExtra(INTENT_EXTRA_ANIMAL_DATA);
detailTextView.setText(animals.getAnimalName());
} else if ((intent.hasExtra(INTENT_EXTRA_PLANET_DATA))) {
final Planets planets = intent.getParcelableExtra(INTENT_EXTRA_PLANET_DATA);
detailTextView.setText(planets.getPlanetName());
}
}
6. Things to remember
- If you are using ViewPager2 along with this RecyclerView version you have to change the dependency from
androidx.viewpager2:viewpager2:1.1.0
toandroidx.viewpager2:viewpager2:1.1.0-alpha01
.
You can check Android Official Release page for newer releases on this version. - While using ConcatAdapter if you have to call item position in adapter, use getBindingAdapterPosition() instead of getAdapterPosition() because we are using multiple adapters at once.
You can check Official Page for more information.
Those were the key features available with the new release.
Now I will add few classes here from example for reference.
AnimalAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class AnimalAdapter extends RecyclerView.Adapter<AnimalAdapter.AnimalViewHolder> {
private final List<Animals> mAnimalList;
private final AnimalAdapterListener mListener;
AnimalAdapter(List<Animals> animalsList, AnimalAdapterListener listener) {
this.mAnimalList = animalsList;
this.mListener = listener;
}
public interface AnimalAdapterListener {
void onAnimalSelected(Animals animals);
}
static class AnimalViewHolder extends RecyclerView.ViewHolder {
private final TextView mAnimalNameTextView;
AnimalViewHolder(@NonNull View itemView) {
super(itemView);
mAnimalNameTextView = itemView.findViewById(R.id.animal_name_item_text_view);
}
}
@NonNull
@Override
public AnimalViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_animals, parent, false);
return new AnimalViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AnimalViewHolder holder, int position) {
final Animals animals = mAnimalList.get(position);
holder.mAnimalNameTextView.setText(animals.getAnimalName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onAnimalSelected(animals);
}
});
}
@Override
public int getItemCount() {
return mAnimalList.size();
}
}
PlanetAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class PlanetAdapter extends RecyclerView.Adapter<PlanetAdapter.PlanetViewHolder> {
private final List<Planets> mPlanetsList;
private final PlanetAdapterListener mListener;
PlanetAdapter(List<Planets> planetsList, PlanetAdapterListener listener) {
this.mPlanetsList = planetsList;
this.mListener = listener;
}
public interface PlanetAdapterListener {
void onPlanetSelected(Planets planets);
}
static class PlanetViewHolder extends RecyclerView.ViewHolder {
private final TextView mPlanetNameTextView;
PlanetViewHolder(@NonNull final View itemView) {
super(itemView);
mPlanetNameTextView = itemView.findViewById(R.id.planet_name_item_text_view);
}
}
@NonNull
@Override
public PlanetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_planets, parent, false);
return new PlanetViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PlanetViewHolder holder, int position) {
final Planets planets = mPlanetsList.get(position);
holder.mPlanetNameTextView.setText(planets.getPlanetName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onPlanetSelected(planets);
}
});
}
@Override
public int getItemCount() {
return mPlanetsList.size();
}
}
MainActivity.java :
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ConcatAdapter;
import androidx.recyclerview.widget.RecyclerView;
import com.developersbreach.concatadapterexample.AnimalAdapter.AnimalAdapterListener;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Animals> mAnimalsList;
private List<Planets> mPlanetsList;
private ConcatAdapter mConcatAdapter;
private AnimalAdapter mAnimalAdapter;
private PlanetAdapter mPlanetAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RecyclerView recyclerView = findViewById(R.id.recycler_view);
addAnimalsToList();
addPlanetsToList();
mAnimalAdapter = new AnimalAdapter(mAnimalsList, new AnimalItemClickListener());
mPlanetAdapter = new PlanetAdapter(mPlanetsList, new PlanetItemClickListener());
mConcatAdapter = new ConcatAdapter(mAnimalAdapter, mPlanetAdapter);
recyclerView.setAdapter(mConcatAdapter);
}
public void removeAnimalAdapter(View view) {
mConcatAdapter.removeAdapter(mAnimalAdapter);
}
public void addAnimalAdapter(View view) {
mConcatAdapter.addAdapter(mAnimalAdapter);
}
public void removePlanetAdapter(View view) {
mConcatAdapter.removeAdapter(mPlanetAdapter);
}
public void addPlanetAdapter(View view) {
mConcatAdapter.addAdapter(mPlanetAdapter);
}
private class AnimalItemClickListener implements AnimalAdapterListener {
@Override
public void onAnimalSelected(Animals animals) {
Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
intent.putExtra(DetailActivity.INTENT_EXTRA_ANIMAL_DATA, animals);
startActivity(intent);
}
}
private class PlanetItemClickListener implements PlanetAdapter.PlanetAdapterListener {
@Override
public void onPlanetSelected(Planets planets) {
Intent intent = new Intent(getApplicationContext(), DetailActivity.class);
intent.putExtra(DetailActivity.INTENT_EXTRA_PLANET_DATA, planets);
startActivity(intent);
}
}
private void addAnimalsToList() {
mAnimalsList = new ArrayList<>();
mAnimalsList.add(new Animals(1, "Cat"));
mAnimalsList.add(new Animals(2, "Dog"));
mAnimalsList.add(new Animals(3, "Giraffe"));
}
private void addPlanetsToList() {
mPlanetsList = new ArrayList<>();
mPlanetsList.add(new Planets(1, "Mercury"));
mPlanetsList.add(new Planets(2, "Pluto"));
mPlanetsList.add(new Planets(3, "Earth"));
}
}
DetailActivity.java :
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class DetailActivity extends AppCompatActivity {
public static final String INTENT_EXTRA_ANIMAL_DATA = "ANIMAL_DATA";
public static final String INTENT_EXTRA_PLANET_DATA = "PLANET_DATA";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
TextView detailTextView = findViewById(R.id.detail_text_view);
Intent intent = getIntent();
if (intent != null) {
if (intent.hasExtra(INTENT_EXTRA_ANIMAL_DATA)) {
final Animals animals = intent.getParcelableExtra(INTENT_EXTRA_ANIMAL_DATA);
detailTextView.setText(animals.getAnimalName() + "\n" + "Id " + animals.getAnimalId());
} else if ((intent.hasExtra(INTENT_EXTRA_PLANET_DATA))) {
final Planets planets = intent.getParcelableExtra(INTENT_EXTRA_PLANET_DATA);
detailTextView.setText(planets.getPlanetName() + "\n" + "Id " + planets.getPlanetId());
}
}
}
}
You can get remaining two model classes Animals.java , Planet.java and layouts from project link below.
Here We Go Again :]
if (article was helful) {
println("Like and subscribe to blog below.")
println("You will receive email for new articles.")
} else {
println("Let me know what i should blog on.")
}
7. Reference and code
Check for RecyclerView releases
ConcatAdapter Documentation
Article by Developer Advocate with use case

Rajasekhar K E
Hi ! I’m Rajasekhar a Programmer who does Android Development, Creative & Technical writing, Kotlin enthusiast and Engineering graduate. I learn from Open Source and always happy to assist others with my work. I spend most of time Training, Assisting & Mentoring students who are absolute Beginners in android development. I’m also running my startup named Developers Breach which mostly works on contributing to open source.
Here We Go Again : (
if (article == helpful) {
println("Like and subscribe to blog newsletter.")
} else {
println("Let me know what i should blog on.")
}
You must be logged in to post a comment.