Android - RecyclerView with one layout, multiple setVisibility
Asked Answered
O

2

4

I have a basically all in one layout which has everything needed for my app's main feed. All variable items (images, video thumbnails.. Etc.) are set to GONE at first and set to VISIBLE when it is needed.

The problem is sometimes, might be due to RecyclerView's recycling behavior, the item which is supposedto be GONE is VISIBLE in the wrong places.

Example :

Item no 1 contains Text

Item no 2 contains Image

Item no 3 contains Image

I keep scrolling down to item no x, then scroll back up and here's what I get :

Item no 1 contains Image from item no x, sometimes item no 3

Item no 2 contains Image

Item no 3 contains Image

I'm using a custom ViewHolder which extends RecyclerView.ViewHolder. The purpose of the CustomViewHolder is for layout declaration and initialization.

    ProgressBar progressBar;
    View viewDimmer;
    RelativeLayout postListWrapper;

    ...

    public ObjectViewHolder(View v) {
        super(v);
        progressBar = (ProgressBar)v.findViewById(R.id.post_inscroll_progressBar);
        viewDimmer = (View)v.findViewById(R.id.post_inscroll_viewDimmer);
        postListWrapper = (RelativeLayout)v.findViewById(R.id.post_inscroll_postListWrapper);
    }

An example of how I load the image :

Picasso.with(context)
    .load(youtubeThumbnailUrl)
    .fit()
    .centerCrop()
    .into(
        ((ObjectViewHolder) holder).userPostYoutubeImage
    );

I've set each visibility to GONE if no url is obtained from the server

((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.GONE);
((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.GONE);

But somehow the image is still reused on the previous items (yes, not only Item no 1). Sometimes image are also in the wrong ImageView. Image D is supposed to be in ImageView D, but it's in ImageView A instead.

Any guide for setting RecyclerView up and going nicely?

If I miss anything, or need to supply more code, please do inform me :D

Overkill answered 31/3, 2016 at 7:38 Comment(0)
J
6

You need to put the else condition too. Like the example below.

// if no url is found from server
if(url == null){
  ((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.GONE);
  ((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.GONE);

} else {
  // Some url has found 
  ((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.VISIBLE);
  ((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.VISIBLE);
}

Do this for each of the items you've got there as the list item in case of you're setting their visibilities in runtime.

Jocular answered 31/3, 2016 at 7:43 Comment(7)
It might be worth saying why this is important. The reason being that Holders are reused.Tret
I just got mind slapped. Thanks Reaz for telling me to use else and thanks @Tret for telling me that the Holders are reused! So the visibility inside the holder number.. 3 for example, is still there even if we move to holder number 1?Overkill
@Tret Many thanks for your add. Yes, this is worth sharing.Jocular
@KevinMurvie Correct. It is more efficient to re-use Holders that pop off the end of the RecyclerView than to create new ones. So whenever you set a property in a Holder, it will keep that property for the next time it is used. So it needs to be reset to defaults.Tret
Alrighty, I'm currently adding else wherever a default reset is needed.. Is my approach correct though? As in using a single layout only..Overkill
Yes. You can proceed with what you're doing now. Should work fineJocular
I realized that I've actually have else statement in the other 2 ImageViews, but not in the first 2 ImageViews, lol. Talk about human errorOverkill
R
0

All your if conditions in onBindViewHolder() must have an else block too.

Don't leave any if condition without else. You can provide a default behaviour in the else block when if condition becomes false.

Richly answered 17/11, 2021 at 5:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.