Bjarn Bronsveld
Bjarn Bronsveld

Reputation: 1029

RecyclerView item content gets mixed up

I've got a RecyclerView containing items with interactive content. Every item contains a textview that's being updated every 5 seconds, but when there are more than 5 items in the RecyclerView, the data gets mixed up.

By example:

Correct: | 1 - 100 |

| 2 - 283 |

| 3 - 382 |

When it gets mixed up:

| 2 - 283 |

| 1 - 100 |

| 3 - 382 |

It's kinda like that, it just gets mixed up.

This happens when I call de adapter.notifyDataSetChanged();

My Adapter:

public class FavoritesAdapter extends RecyclerView.Adapter {

private List<Favorites> channels;
private Context context;

public FavoritesAdapter(Context context, List<Favorites> channels) {
    this.context = context;
    this.channels = channels;
}

@Override
public FavoritesViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.favoriteitem_layout, viewGroup, false);
    FavoritesViewHolder pvh = new FavoritesViewHolder(v);
    return pvh;
}

@Override
public void onBindViewHolder(final FavoritesViewHolder holder, final int position) {
    final DBHelper dbHelper = new DBHelper(context);
    if (Data.isConnected(context)) {
        Scheduler.getInstance().doAsync(new Scheduler.Task<Object, Channel>() {
            @Override
            public Channel run(Object... params) {
                return Methods.getData(channels.get(position).getChannelId(), channels.get(position).getChannelName(), true, context);
            }
        }, new Scheduler.Executable<Channel>() {
            @Override
            public void execute(Channel result) {

                if(result.getId() != "") {
                    if(!result.channelSubs.equalsIgnoreCase("-500_RTSS_ERROR")) {
                        holder.channelSubsView.setText(result.getSubs());
                        holder.channelTitleSubsView.setText(String.valueOf(channels.get(position).getChannelName()) + "'s Suscribers");
                        channels.get(position).setChannelSubs(result.getSubs());
                        dbHelper.updateFavorites(channels.get(position));
                    }
                    else {
                        holder.channelSubsView.setText(channels.get(position).getChannelSubs());
                        holder.channelTitleSubsView.setText(String.valueOf(channels.get(position).getChannelName()) + "'s Suscribers (Cached)");
                    }
                }
                else {
                    holder.channelSubsView.setText(channels.get(position).getChannelSubs());
                    holder.channelTitleSubsView.setText(String.valueOf(channels.get(position).getChannelName()) + "'s Suscribers (Cached)");
                }
            }
        });
    }
    else {
        holder.channelSubsView.setText(channels.get(position).getChannelSubs());
        holder.channelTitleSubsView.setText(String.valueOf(channels.get(position).getChannelName()) + "'s Suscribers (Cached)");
    }

    Picasso.with(context).load(channels.get(position).getChannelAvatar())
            .error(R.drawable.youtube_default_avatar)
            .placeholder(R.drawable.youtube_default_avatar)
            .into(holder.channelAvatarView);

    holder.channelCardView.setOnClickListener(clickListener);
    holder.channelCardView.setTag(holder);
}

View.OnClickListener clickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        FavoritesViewHolder holder = (FavoritesViewHolder) view.getTag();
        int position = holder.getPosition();

        Favorites channel = channels.get(position);
        if(Data.isConnected(context)) {
            Methods.getYouTubeData(channel.getChannelId(), channel.getChannelName(), channel.getChannelAvatar(), context);
        }
        else {
            Toast.makeText(context, R.string.error_connection_no_internet, Toast.LENGTH_LONG).show();
        }
    }
};

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

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

public static class FavoritesViewHolder extends RecyclerView.ViewHolder {
    CardView channelCardView;
    TextView channelSubsView;
    TextView channelTitleSubsView;
    ImageView channelAvatarView;

    FavoritesViewHolder(View itemView) {
        super(itemView);
        channelCardView = (CardView) itemView.findViewById(R.id.channelCardView);
        channelSubsView = (TextView) itemView.findViewById(R.id.subsAmount);
        channelTitleSubsView = (TextView) itemView.findViewById(R.id.subsText);
        channelAvatarView = (ImageView) itemView.findViewById(R.id.channelAvatarView);
    }
}

}

Upvotes: 3

Views: 1930

Answers (2)

Rohit Arya
Rohit Arya

Reputation: 6791

You are making an asynchronous call in onBindViewHolder so when the response of the async tasks comes, it reads wrong position from public void onBindViewHolder(final FavoritesViewHolder holder, final int position) because by that time position returned by onBindViewHolder has changed.

What you can do is, pass the position into async task as a parameter and deliver the same position in the result of the async task. That way call made for position p (say) will be applied to p.

Along with that, also try to use getAdapterPosition instead of getPosition (deprecated and creates confusion) on RecyclerViewHolder.

Upvotes: 2

Pulkit Kumar
Pulkit Kumar

Reputation: 101

Can you check if you are editing the order/ sorting of the initial list passed to the constructor of the adapter.

 List<Favorites> channels = getChannels();
 adapter = new FavoritesAdapter(context, channels);
 recyclerView.setAdapter(adapter)
 //     edit or sort *channels*
 adapter.notifyDataSetChanged();

Upvotes: 0

Related Questions