Reputation: 1641
In my app, I'm showing the articles which are getting fetched from a webservice. Those articles have title, image and other fields. For displaying the images, I'm using Picasso.
Problem - While scrolling the RecyclerView, I'm seeing the images getting misplaced. Some items are having the duplicate images. I know it is RecyclerView which reuses the xml item layout and because of that it is creating a problem. But I think there must be some solution to this problem. I've googled about this and found some posts on stackoverflow but that didn't help. For example-
Picasso loads pictures to the wrong imageview in a list adapter
I've tried the following but having the same problem-
public class ArticleAdapter extends RecyclerView.Adapter<ArticleAdapter.ArticleViewHolder> {
protected Activity mActivity;
protected List<Article> mItems = new ArrayList<>();
private static OnEntityClickCallback mCallback;
public ArticleAdapter(Activity pActivity) {
mActivity = pActivity;
}
public void setItemClickCallback(OnEntityClickCallback pCallback) {
this.mCallback = pCallback;
}
@Override
public ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View articleView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_article_item, parent, false);
return new ArticleViewHolder(articleView);
}
public void addItem(List<Article> moreItems) {
mItems.addAll(moreItems);
notifyDataSetChanged();
}
public void removeItems(){
mItems.clear();
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bind(mItems.get(position));
}
@Override
public int getItemCount() {
return mItems.size();
}
static class ArticleViewHolder extends RecyclerView.ViewHolder {
private TextView tvTitle;
TextView tvAuthor;
TextView tvPostdate;
ImageView imgImage;
RatingBar ratingBar;
public ArticleViewHolder(View view) {
super(view);
this.tvTitle = (TextView) view.findViewById(R.id.tv_title);
this.tvAuthor = (TextView) view.findViewById(R.id.tv_author);
this.tvPostdate = (TextView) view.findViewById(R.id.tv_date);
this.imgImage = (ImageView) view.findViewById(R.id.img_image);
this.ratingBar = (RatingBar) view.findViewById(R.id.ratingBar);
}
public void bind(final Article article) {
tvTitle.setText(article.getTitle());
tvPostdate.setText(article.getPostdate());
tvAuthor.setText(article.getAuthor());
// Canceling the older request
Picasso.with(imgImage.getContext()).cancelRequest(imgImage);
// Creating a new request.
if (article.getImage() != null) {
Picasso.with(imgImage.getContext()).load(article.getImageUrl())
.placeholder(R.drawable.noimage)
.error(R.drawable.noimage)
.into(imgImage);
}
this.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mCallback != null)
mCallback.onEntitySelected(article);
}
});
}
}
}
Update - Part of my layout file
<ImageView
android:id="@+id/img_image"
android:layout_width="match_parent"
android:layout_height="@dimen/cardview_image_thumbnail_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:layout_margin="@dimen/cardview_padding_btw_widgets"
android:src="@drawable/noimage"
/>
Any help would be appreciated. Thank you.
Upvotes: 13
Views: 7161
Reputation: 21551
Also, it worked for me:
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
These methods are a cleaner approach to accessing the list's data.
Upvotes: 2
Reputation: 177
Your view is reused.
Call Picasso.with(imgImage.getContext()).cancelRequest(imgImage);
to cancel any existing requests of your ImageView.
Then you can load your image if article.getImage() != null
and provide a fallback if your article image is null like imgImage.setImageDrawable(R.drawable.some_drawable);
Upvotes: 0
Reputation: 5375
Externally set the drawable because you are getting the imageview which has some drawable already attached to it. Imageview is not getting recreated so the previous image in the ImageView will be visible until you remove it.
if (article.getImage() != null) {
Picasso.with(imgImage.getContext()).load(article.getImageUrl())
.placeholder(R.drawable.noimage)
.error(R.drawable.noimage)
.into(imgImage);
}else{
// imgImage.setImageDrawable(null);
imgImage.setImageDrawable(R.drawable.some_drawable);
}
Upvotes: 12
Reputation: 1556
Use setTag in onBindViewHolder it will hold data and your images will not misplace.
@Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bind(mItems.get(position));
holder.imgImage.setTag(mItems.get(position));
}
OR
Maybe try your approach maybe it works
@Override
public void onBindViewHolder(ArticleViewHolder holder, int position) {
holder.bind.setTag(mItems.get(position));
}
Upvotes: 0