Sam
Sam

Reputation: 3155

Multiple ViewHolder RecycleVIew List rearrange

I tried to find the solution but I think nobody had such a problem.

So I have been using ListView in most of my projects and I feel it is more flexible in terms of not having to Bind with ViewHolder as you need to do in RecyclerView. But since I needed to make a horizontal listview I could easily do that with LayoutManager using RecyclerView. It works perfectly.

But now I am using multiple ViewHolders for RecyclerView because I need to display different views for different items of the RecyclerView. It again works perfectly using the code below.

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

    private List<Item> data;
    private Context context;

    // Item.Type is an enum, used to differentiate the view types.

    public MyAdapter(List<Item> list, Context context) {
        this.data = list;
        this.context = context;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(data.get(viewType).getType() == TYPEA) {
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_a, parent, false);
            return new ViewHolderA(itemView);
        }
        else {
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_b, parent, false);
            return new ViewHolderB(itemView);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if ( data.get(position).getType()== TYPEA ){
            ViewHolderA viewHolder = (ViewHolderA) holder;
            ...

        }
        else if (data.get(position).getType()== TYPEB){
            ViewHolderB viewHolder = ((ViewHolderB) holder);
            ...            
        }
    }


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


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

}

So the problem arises when I rearrange the list used to display the items. For instance, I start off with 1 item in the list of TYPEB, it is displayed correctly. But now I want to add new item in the list but at the start, so that TYPEB is pushed back. So i add a new item of TYPEA and the list looks like [TYPEA,TYPEB]. ViewHolderA is for TYPEA and similarly ViewHolderB for TYPEB

In this situation the line inside onBindViewHolder

ViewHolderA viewHolder = (ViewHolderA) holder;

Throws me an error saying that ViewHolderB can not be cast to ViewHolderA. That shows after rearranging the list, the adapter is calling onBindViewHolder with wrong ViewHolder instance against the positon. Any idea how to approach this.

Upvotes: 2

Views: 342

Answers (1)

Alexei Artsimovich
Alexei Artsimovich

Reputation: 1184

You need to specify a unique id here, you don't have to return the position:

@Override
public int getItemViewType(int position) {        
    return data.get(position).getType()
}

And of course you have to use the viewType parameter as a type not as a position:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if(viewType == TYPEA) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_a, parent, false);
        return new ViewHolderA(itemView);
    }
    else {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_b, parent, false);
        return new ViewHolderB(itemView);
    }
}

Upvotes: 2

Related Questions