当在RecyclerView中使用Picasso图片时出现图片错位问题

13

我的应用程序从网络服务获取文章并显示其标题、图片和其他字段。为了显示图片,我使用Picasso

问题 - 在滚动RecyclerView时,我发现图片位置错乱。有些项具有重复的图像。我知道这是由于RecyclerView重用xml项布局导致的问题。但我认为必须存在解决此问题的方法。我已经在stackoverflow上搜索了一些帖子,但都没有帮助。例如:

Picasso loads pictures to the wrong imageview in a list adapter

我尝试过以下方法,但问题仍然存在:

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);
        }
    });
}

    }
}

更新 - 我的布局文件的一部分

 <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"
                    />

希望得到任何形式的帮助,感谢。


只有图片被错放了还是文字也错了? - Soham
@Soham 只有图片位置错乱了。 - Rahul Chaurasia
请问您能够发布您的适配器类吗? - Soham
@Soham 已添加了适配器类,请检查。 - Rahul Chaurasia
4个回答

12

因为您正在获取已经附加了某些可绘制对象的ImageView,所以需要外部设置可绘制对象。ImageView不会被重新创建,因此在删除之前,ImageView中先前的图像将保持可见。

    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);
    }

1
我在这里没有看到任何变化。你能否详细说明一下? - Rahul Chaurasia
1
检查这一行else{ imgImage.setImageDrawable(null); }。实际上发生的是您的ImageView被回收并且它拥有上次的图像。因此,如果imageUrl为空,您应该删除该ImageView中存在的任何drawable。告诉我这是否有效。 - Ankit Aggarwal
好的。但是我在xml布局中有一个默认图像。如果图像url为空,我希望显示该图像。 - Rahul Chaurasia
实际上,您必须外部设置可绘制对象,因为您正在获取已附加到其中的某些可绘制对象的ImageView。 ImageView不会重新创建,因此在外部设置之前,XML布局中的默认图像将不可见。 - Ankit Aggarwal
现在已编辑答案。 - Ankit Aggarwal
显示剩余4条评论

2

此外,这对我也起作用:

@Override
public long getItemId(int position) {
    return position;
}

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

这些方法是访问列表数据的更清晰方式。

0

您的视图被重复使用。

调用Picasso.with(imgImage.getContext()).cancelRequest(imgImage);取消您的ImageView中任何现有的请求。

然后,如果article.getImage() != null,您可以加载您的图片,并提供一个回退选项,如果您的文章图片为空,则使用imgImage.setImageDrawable(R.drawable.some_drawable);


0
在onBindViewHolder中使用setTag,它将保存数据,使您的图像不会错位。
@Override
    public void onBindViewHolder(ArticleViewHolder holder, int position) {
        holder.bind(mItems.get(position));
        holder.imgImage.setTag(mItems.get(position));
    }

或者尝试你的方法,也许会奏效

@Override
    public void onBindViewHolder(ArticleViewHolder holder, int position) {
        holder.bind.setTag(mItems.get(position));
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接