RecyclerView和Picasso图片在滚动后消失

5

我在这里没有找到答案,也没有在这里这里找到。

我有一个显示帖子列表的活动(带或不带图片)。当我向下滚动并向上滚动或使用SwipeRefreshLayout刷新列表时,一些图片可能会消失。我使用RecyclerView来显示帖子列表,并使用Picasso来加载图片。以下是我的适配器绑定:

@Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
    // <...>
    if (item.getPhoto() != null) {
        Picasso.with(context)
                .load(item.getPhoto())
                .into(holder.mPostPhoto);
    } else {
        holder.mPostPhoto.setImageDrawable(null);
        holder.mPostPhoto.setVisibility(View.GONE);
    }
}

我发送HTTP请求以获取帖子,当我有新数据时,调用PostsAdapter:
public void addAll(List<PostResponse> items) {
    this.items.clear();
    this.items.addAll(items);

    notifyDataSetChanged();
}

在MainActivity中:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // <...>
    mPostAdapter = new PostAdapter();
    mPosts.setLayoutManager(new LinearLayoutManager(MainActivity.this));
    mPosts.setAdapter(mPostAdapter);

    mPostsSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            updatePosts();
        }
    });

    updatePosts();
}

private void updatePosts() {
    new Api(this).getPosts(new GetPostsCallback(this) {
        @Override
        public void onSuccess(final Paging<PostResponse> paging) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mPostAdapter.addAll(paging.getData());
                    mPostsSwipeRefresh.setRefreshing(false);
                }
            });
        }
    });
}

我觉得这很基础,不明白为什么图片会一次又一次地消失。我的列表并不长,图片在上传到服务器之前已经调整大小,它们不应该占用太多内存。最糟糕的是,当它们消失时,它们不会重新加载。只有在我向下滚动然后向上滚动后才会重新加载...

  • 请解释一下为什么会出现这种情况。
  • 我该如何解决这个问题?

谢谢!


很难说你发布的代码为什么会出现这种情况。你能分享更多信息吗?你有针对Picasso的特定配置策略吗? - Blackbelt
@Blackbelt 请看最新更新。我没有任何特定配置。非常基础:从服务器获取帖子,每个帖子都有图片URL,使用 Picasso 按照 URL 将图像加载到 ImageView中。 - Andrei
如果你记录 item.getPhoto(),看起来不错。 - Blackbelt
@Blackbelt 我检查了 item.getPhoto(),它在那里... - Andrei
5个回答

10

我也遇到了这个问题,但是不想禁用回收。我发现通过在调用 Picasso 之前将 ImageView 的可见性明确设置为 View.VISIBLE,即使滚动后仍然可以加载图像:

holder.image.setVisibility(View.VISIBLE);
Picasso.with(context)
    .load(imgUrl)
    .into(holder.image);

1
这是正确的答案,请接受它以便其他人知道它可行。 - Kaustubh Bhagwat
1
@Billy Brawner,非常感谢你,你救了我的一天!这应该是正确的答案。 - Shahriar Siraj Snigdho
@William,它确实完美地工作了,但你能解释一下错误的原因吗? - chris
1
@chris,距离我上次看这个已经过去几年了,但至少在问题的示例代码中,如果没有图像,则ImageView的可见性被设置为View.GONE,但当视图在未来被重用时,它从未被设置回View.VISIBLE。由于RecyclerView只会创建一次视图,然后对其进行回收利用(因此得名),即使与视图关联的数据已更改,该可见性状态也会保持不变。 - William Brawner

3

所以,显然RecyclerView从我的列表中回收了一些项目,之后由于某种原因无法重新加载图像。好问题“为什么?”...也许是因为我做错了什么,不确定。这对我有帮助:

recyclerView.getRecycledViewPool().setMaxRecycledViews(0, 0);

基本上,您正在关闭项目回收。这对我有用,因为我不会渲染大量的项目列表。

如果您不想回收利用东西,为什么还要使用RecyclerView呢? - Huzefa Gadi
@HuzefaGadi 我确实想使用recyclerView。问题在于它的工作不如预期。 - Andrei
你救了我的命,伙计。 - Dracarys
1
@Dracarys 哈哈,很高兴听到这个好消息:D - Andrei

2
如果您正在适配器中使用if条件,请尝试以下代码。
    if (model.image == null || model.equals(""))
        viewHolder.ivIndieImage.setVisibility(View.GONE);
    else{
        viewHolder.ivIndieImage.setVisibility(View.VISIBLE);
      }

尝试将图像的可见性设置为可见。

0

在onBindViewHolder方法中,有一个问题需要注意。你在else部分把控件的可见性设置为View.GONE,但是在If部分没有把控件再次设置为可见。因此,在recycler view中,视图被回收并且它们的数据被更新,但如果你修改了任何属性,它将仍然保持相同的状态,并且会显示在使用同一回收视图显示的其他项中。


0

我通过移除相同的调整大小和中心裁剪方法来解决了这个问题,不知怎么地它们占用了太多内存,导致图像加载过程混乱。


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