As you know, if we want to implement multiple types in RecyclerView
Here you can use Dynamic method dispatch. Below i share my idea. //Activity Code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ArrayList<Object> dataList = new ArrayList<>();
dataList.add("Apple");
dataList.add("Orange");
dataList.add("Cherry");
dataList.add("Papaya");
dataList.add("Grapes");
dataList.add(100);
dataList.add(200);
dataList.add(300);
dataList.add(400);
ViewAdapter viewAdapter = new ViewAdapter(dataList);
recyclerView.setAdapter(viewAdapter);
}
}
//Adapter code
public class ViewAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private ArrayList<Object> dataList;
public ViewAdapter(ArrayList<Object> dataList) {
this.dataList = dataList;
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
BaseViewHolder baseViewHolder;
if(viewType == 0) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_one,parent,false);
baseViewHolder = new ViewHolderOne(view);
}else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_two,parent,false);
baseViewHolder = new ViewHolderSecond(view);
}
return baseViewHolder;
}
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
holder.bindData(dataList.get(position));
}
@Override
public int getItemViewType(int position) {
Object obj = dataList.get(position);
int type = 0;
if(obj instanceof Integer) {
type = 0;
}else if(obj instanceof String) {
type = 1;
}
return type;
}
@Override
public int getItemCount() {
return dataList != null ? dataList.size() : 0;
}
}
//Base View Holder Code.
public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {
public BaseViewHolder(View itemView) {
super(itemView);
}
public abstract void bindData(T data);
}
//View Holder One Source Code.
public class ViewHolderOne extends BaseViewHolder<Integer> {
private TextView txtView;
public ViewHolderOne(View itemView) {
super(itemView);
txtView = itemView.findViewById(R.id.txt_number);
}
@Override
public void bindData(Integer data) {
txtView.setText("Number:" + data);
}
}
//View Holder Two
public class ViewHolderSecond extends BaseViewHolder<String> {
private TextView textView;
public ViewHolderSecond(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.txt_string);
}
@Override
public void bindData(String data) {
textView.setText("Text:" + data);
}
}
For project Source: enter link description here
It might not be the answer you're expecting but here is an example using Epoxy, which really makes your life easier:
First you define your models:
@EpoxyModelClass(layout = R.layout.header_view_model)
public abstract class HeaderViewModel extends EpoxyModel<TextView> {
@EpoxyAttribute
String title;
@Override
public void bind(TextView view) {
super.bind(view);
view.setText(title);
}
}
@EpoxyModelClass(layout = R.layout.drink_view_model)
public abstract class DrinkViewModel extends EpoxyModel<View> {
@EpoxyAttribute
Drink drink;
@EpoxyAttribute
Presenter presenter;
@Override
public void bind(View view) {
super.bind(view);
final TextView title = view.findViewById(R.id.title);
final TextView description = view.findViewById(R.id.description);
title.setText(drink.getTitle());
description.setText(drink.getDescription());
view.setOnClickListener(v -> presenter.drinkClicked(drink));
}
@Override
public void unbind(View view) {
view.setOnClickListener(null);
super.unbind(view);
}
}
@EpoxyModelClass(layout = R.layout.food_view_model)
public abstract class FoodViewModel extends EpoxyModel<View> {
@EpoxyAttribute
Food food;
@EpoxyAttribute
Presenter presenter;
@Override
public void bind(View view) {
super.bind(view);
final TextView title = view.findViewById(R.id.title);
final TextView description = view.findViewById(R.id.description);
final TextView calories = view.findViewById(R.id.calories);
title.setText(food.getTitle());
description.setText(food.getDescription());
calories.setText(food.getCalories());
view.setOnClickListener(v -> presenter.foodClicked(food));
}
@Override
public void unbind(View view) {
view.setOnClickListener(null);
super.unbind(view);
}
}
Then you define your Controller
:
public class DrinkAndFoodController extends Typed2EpoxyController<List<Drink>, List<Food>> {
@AutoModel
HeaderViewModel_ drinkTitle;
@AutoModel
HeaderViewModel_ foodTitle;
private final Presenter mPresenter;
public DrinkAndFoodController(Presenter presenter) {
mPresenter = presenter;
}
@Override
protected void buildModels(List<Drink> drinks, List<Food> foods) {
if (!drinks.isEmpty()) {
drinkTitle
.title("Drinks")
.addTo(this);
for (Drink drink : drinks) {
new DrinkViewModel_()
.id(drink.getId())
.drink(drink)
.presenter(mPresenter)
.addTo(this);
}
}
if (!foods.isEmpty()) {
foodTitle
.title("Foods")
.addTo(this);
for (Food food : foods) {
new FoodViewModel_()
.id(food.getId())
.food(food)
.presenter(mPresenter)
.addTo(this);
}
}
}
}
Initialize your Controller
:
DrinkAndFodController mController = new DrinkAndFoodController(mPresenter);
mController.setSpanCount(1);
final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 1);
layoutManager.setSpanSizeLookup(mController.getSpanSizeLookup());
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mController.getAdapter());
And finally you can add your data as easily as this:
final List<Drink> drinks = mManager.getDrinks();
final List<Food> foods = mManager.getFoods();
mController.setData(drinks, foods);
You'll have a list thats looks like:
Drinks
Drink 1
Drink 2
Drink 3
...
Foods
Food1
Food2
Food3
Food4
...
For more informations you can check the wiki.
Second one is buggy because when ViewHolders get recycled it produces unexpected behavior. I considered changing visibility during binding but it isn't performant enough for large amount of Views. Recycler inside RecyclerView stores ViewHolders per type so first way is more performant.