Poonam Sharma
Poonam Sharma

Reputation: 33

RecyclerView Multiple View types (View Holders) Handle item Selection count state

I'm having a sectioned recyclerview with title header and items under that catergoty. I have two viewHolders one for the title, and other for the items that come under that category. Here is my Adapter.

public class MenuAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {


public static final String TAG = MenuAdapter.class.getSimpleName();
private Context mContext;
private ItemClickListener itemClickListener;
private List<HeterogeneousObject> heterogeneousObjects;

public MenuAdapter(Context mContext, CartHelper helper) {
    this.mContext = mContext;
    heterogeneousObjects = new ArrayList<>();

}

public void itemClickListenerCallback(ItemClickListener itemClickListenerCallback) {
    this.itemClickListener = menuItemClickListenerCallback;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    if (viewType == 0) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_cuisine_rv, parent, false);
        return new MenuAdapterViewHolder(view);

    } else {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_cuisine_menu_items, parent, false);
        return new RecycledGridViewHolder(view);
    }

}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
    HeterogeneousObject object = heterogeneousObjects.get(position);
    if (object.getItemType() == 0) {
        if (object.getCuisine() != null) {
            MenuAdapterViewHolder holder = (MenuAdapterViewHolder) viewHolder;
            holder.cuisineName.setText(object.getCuisine().getCuisine_name());

        }
    } else {
        if (object.getMenuItem() != null) {
            RecycledGridViewHolder holder = (RecycledGridViewHolder) viewHolder;
            holder.dishName.setText(object.getMenuItem().getItemName());
            holder.dishPrice.setText(mContext.getString(R.string.rupee_symbol, object.getMenuItem().getItemPrice() * 0.01));

            if (object.getMenuItem().getIsVeg()) {
                holder.vegNonVegIndicator.setImageDrawable(mContext.getResources().getDrawable(R.drawable.veg_symbol));
                //holder.vegNonVegIndicator.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_veg_indicator));
            } else if (!object.getMenuItem().getIsVeg()) {
                holder.vegNonVegIndicator.setImageDrawable(mContext.getResources().getDrawable(R.drawable.non_veg_symbol));
                //holder.vegNonVegIndicator.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_non_veg_indicator));
            }
            Single<CartSelection> selection = cartHelper.getCartSelectionById(Long.parseLong(object.getMenuItem().getItemId()));
            selection.subscribe(new DisposableSingleObserver<CartSelection>() {
                @Override
                public void onSuccess(CartSelection cartSelection) {
                    if (cartSelection != null) {
                        holder.incDecButton.setNumber(cartSelection.getQty(), true);
                    }
                }

                @Override
                public void onError(Throwable e) {

                }
            });
            holder.bind(object.getMenuItem(), menuItemClickListener);
        }
    }

}


@Override
public int getItemCount() {
    return heterogeneousObjects.size();
}

@Override
public int getItemViewType(int position) {
    super.getItemViewType(position);
    if (heterogeneousObjects.get(position).getItemType() == 0) {
        return 0;
    } else {
        return 1;
    }
}

}

Here is my View Holder 1

public class RecycledGridViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.tv_si_dish_name)
    TextView dishName;
    @BindView(R.id.tv_si_dish_price)
    TextView dishPrice;

    @BindView(R.id.btn_id_item_dish_grid)
    IncDecButton incDecButton;
    @BindView(R.id.iv_veg_non_veg_grid)
    AppCompatImageView vegNonVegIndicator;

    public RecycledGridViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    public void bind(final MenuItem menuItem, final MenuItemClickListener menuItemClickListener) {
        incDecButton.setOnButtonsClickedListener(new IncDecButton.OnButtonsClickedListener() {
            @Override
            public void onPlusClicked(int num) {

                if (menuItem.getCustomizable()) {
                    menuItemClickListener.onCustomizableItemClicked(menuItem, 1);
                    if (incDecButton.getNumber() == 0) {
                        incDecButton.setNumber(0, true);
                    }
                } else {
                    menuItemClickListener.onPlusButtonClicked(menuItem, num);
                }
            }

            @Override
            public void onMinusClicked(int num) {
                if (menuItem.getCustomizable()) {
                    menuItemClickListener.onCustomizableItemClicked(menuItem, 0);
                } else {
                    menuItemClickListener.onMinusButtonClicked(menuItem, num);
                }
            }
        });

}

View Holder 2

  class MenuAdapterViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.tv_cuisine_name_menu_v2)
    TextView cuisineName;


    public MenuAdapterViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

I'm maintaining a state of item count that the list item in ViewHolder 1 has to show in IncDecButton outside of the ViewHolder in a ROOM Db Dao, which i query as onBindViewHolder is called for each item but the views gets recycled and item count gets misplaced.

when i only have a single view holder, i.e only View Holder 1, item counts have no issues, but it gets recycled and misplaced when there are 2 View Holders. I don't really seem to understand what am i doing wrong.

This code works fine with only a single Viewholder (Single Item Type RecyclerView).

Upvotes: 3

Views: 1571

Answers (1)

Juanje
Juanje

Reputation: 1315

Views in a RecyclerView are recycled when dissapear in the screen. You should manage the state outside the ViewHolder and just use it for the presentation. You could store the current value of the count in the item data you pass to the adapter and then just show this current value in the ViewHolder.

Another important thing is to set always the value. If you do not put the correct value, the ViewHolder will maintain the recycled view, so if the count for new cells is 0, just put 0 in the binding.

Hope it helps.

Upvotes: 2

Related Questions