Jolson Jolson - 23 days ago 17
Android Question

SparseBooleanArray prob used in horizontal Recycleview inside Vertical RecycleView

I have

horizontalRecycleView
inside
verticalRecycleview
. and I have made horizontatRecycleView selectable using SparseBooleanArray. So every user clicks on an item from Horizontal list I change the background of that position.

The problem is
SparseBooleanArray
initialized for each view/row uses same physical address I guess. Because every position I select reflects on all horizontal list.

here is my code:

RecycleView-Vertical:

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

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 3:
return new HorizontalListHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_adapter_recycleview_horizontal, parent, false));
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (type) {
int type = chatAdapterModels.get(position).getVIEWTYPE();

case HORIZONTAL_LIST:
HorizontalListHolder viewHolder = (HorizontalListHolder) holder;
viewHolder.chatHorizontalAdapter.updateData(chatAdapterModels.get(position).getChatHorizontalModels());
break;
}
}

public final class HorizontalListHolder extends RecyclerView.ViewHolder {
ChatHorizontalAdapter chatHorizontalAdapter = null;
private SparseBooleanArray sparseBooleanArray;

@BindView(R.id.recycle_view)
RecyclerView recyclerView;

public HorizontalListHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
sparseBooleanArray = new SparseBooleanArray();

chatHorizontalAdapter = new ChatHorizontalAdapter(context, sparseBooleanArray);
chatHorizontalAdapter.onItemClickListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
recyclerView.setAdapter(chatHorizontalAdapter);
}
}
}


Horizontal-RecycleView

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

private Context context;
private ChatHorizontalAdapter.ClickListner clickListner;
ArrayList<ChatHorizontalModel> horizontalModels;
private SparseBooleanArray sparseBooleanArray;

private int lastPosition;

public ChatHorizontalAdapter(Context activity, SparseBooleanArray sparseBooleanArray) {

context=activity;
this.sparseBooleanArray=sparseBooleanArray;
}

public void updateData(ArrayList<ChatHorizontalModel> horizontalModels,int viewType){
this.horizontalModels=horizontalModels;
notifyDataSetChanged();
// sparseBooleanArray.clear();
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case 1: return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_recycle_adapter_view, parent, false));
// case 2: return new something
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder viewHolder = (ViewHolder) holder;
String strings=horizontalModels.get(position).getStr();
viewHolder.textView.setText(strings);
viewHolder.imageView.setImageResource(horizontalModels.get(position).getImages());
changeBackgroundColor(sparseBooleanArray.get(position),viewHolder.cardView,viewHolder.imageView,viewHolder.textView,horizontalModels.get(position).getImages());

}

@Override
public int getItemViewType(int position) {
return viewType;
}

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

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@BindView(R.id.mainCardView)CardView cardView;
@BindView(R.id.image)ImageView imageView;
@BindView(R.id.textView)TextView textView;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
cardView.setOnClickListener(this);
}

@Override
public void onClick(View view) {
if(clickListner!=null){
clickListner.onItemClick(getAdapterPosition());

handleSelection(getAdapterPosition());
notifyDataSetChanged();
}
}
}

public interface ClickListner {
void onItemClick(int position);
}

public void onItemClickListener(ChatHorizontalAdapter.ClickListner clickListner){
this.clickListner=clickListner;
}

public void handleSelection(int position){
sparseBooleanArray.clear();
for (int i = 0; i <=horizontalModels.size() ; i++) {
if (i==position) {
sparseBooleanArray.put(i, true);
} else {
sparseBooleanArray.put(i,false);
}
}
}

public void changeBackgroundColor(boolean set, View cardView, ImageView imageView, TextView textView, int images){
// change bck color of selected item
}
}

Answer

RecyclerView doesn't create a view to each row in your list, if you have 100 rows, it will create maybe about 7 or 8 " just the number visible on your screen" so you will have about 7 or 8 SparseBooleanArray and it will reuse them with all rows, so a change in one row will affect another if it uses the same view reference.
You should create an ArrayList<SparseBooleanArray> with a number that matches your rows count in the VerticalAdapter and update the SparseBooleanArray inside HorizontalAdapter when onBindViewHolder() is called

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    HorizontalListHolder viewHolder = (HorizontalListHolder) holder;
    // Where mSparseList is ArrayList<SparseBooleanArray>
    viewHolder.updateSparseArray(mSparseList.get(position));
}

and in the horizontal adapter add the method updateSparseArray() that updates the SparseBooleanArray data.

Comments