Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android listview with Glide - doubled bitmaps after load

I'm developing an android application. One of my fragments contains a simple listview showing friend list. Each friend can have its own profile image - it is set by the Glide library. When user has no profile pic set the default image is shown. My problem is, that every time, first element on the list gets the same picture which is set on the last element of the list which is not default picture. What i mean is shown on pic:

doubled profile pic

user with name wiktor has set profile picture and as you see the first position bonzo has wiktor's profile pic ( bonzo should have default pic )

there is also a problem with deleting user form list:

list after delete

as you see, i removed majka from friend list and next elements gets her picture.

The default profile picture is set in inside row layout xml from drawables.

Here is code of my listview adapter:

public class FriendsAdapter extends ArrayAdapter<FriendData> {

static class FriendHolder {

    TextView friendName;
    TextView friendRank;
    ImageView friendIcon;
    ImageButton deleteFriendBtn;
    ImageButton banFriendBtn;
}

private List<FriendData> list;

public FriendsAdapter(Context context, int resource, List<FriendData> objects) {

    super(context, resource, objects);
    list = objects;
}

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {

    final FriendData element = getItem(position);
    final FriendHolder viewHolder;
    if (convertView == null) {

        viewHolder = new FriendHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.friend_layout, parent, false);
        viewHolder.friendIcon = (ImageView) convertView.findViewById(R.id.friendIcon);
        viewHolder.friendName = (TextView) convertView.findViewById(R.id.friendName);
        viewHolder.friendRank = (TextView) convertView.findViewById(R.id.friendRank);
        viewHolder.deleteFriendBtn = (ImageButton) convertView.findViewById(R.id.deleteFriendBtn);
        viewHolder.banFriendBtn = (ImageButton) convertView.findViewById(R.id.banFriendBtn);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (FriendHolder) convertView.getTag();
    }

    if (element.getPhoto() != null) {

        String photo = S3ImageHandler.SMALL_PROFILE_ICON_PREFIX + element.getPhoto();
        String url = String.format(S3ImageHandler.AMAZON_PROFILE_DOWNLOAD_LINK, photo);
        Glide.with(getContext())
                .load(url)
                .asBitmap()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .placeholder(R.drawable.user_small)
                .into(new BitmapImageViewTarget(viewHolder.friendIcon) {
                    @Override
                    protected void setResource(Bitmap resource) {

                        RoundedBitmapDrawable circularBitmapDrawable = RoundedBitmapDrawableFactory.create(getContext().getResources(), resource);
                        circularBitmapDrawable.setCircular(true);
                        viewHolder.friendIcon.setImageDrawable(circularBitmapDrawable);
                    }
                });
    }

    viewHolder.friendName.setText(element.getId());
    viewHolder.friendRank.setText(String.format("%s %d", getContext().getString(R.string.text_rank), element.getRank()));
    viewHolder.deleteFriendBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
            confirmDelete(element, position, parent);
        }
    });
    viewHolder.banFriendBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            confirmBan(element, position, parent);
        }
    });

    return convertView;
}

removing user from friend list:

        remove(element);
        notifyDataSetChanged();

does any of you see what i do wrong ? i would be very grateful for some help. thank you :)

like image 480
Dominik Avatar asked Dec 18 '22 20:12

Dominik


1 Answers

You're resuing list items (by definition of recycler view) which means that if an image was set to an item and you don't clear it, the image will remain there. So even though setText changes the labels viewHolder.friendIcon is not touched. The fix is really simple:

if (element.getPhoto() != null) {
    Glide.with(getContext())...
} else {
    Glide.clear(viewHolder.friendIcon); // tell Glide that it should forget this view
    viewHolder.friendIcon.setImageResource(R.drawable.user_small); // manually set "unknown" icon
}

Also remove the drawable from the xml, or at least change to tools:src which will help reducing the inflation time; the value is overwritten by Glide every time anyway.


To reduce complexity there's an alternative:

class FriendData {
    // if you can't modify this class you can also put it in a `static String getPhotoUrl(Element)` somewhere
    public void String getPhotoUrl() {
        if (this.getPhoto() == null) return null;
        String photo = S3ImageHandler.SMALL_PROFILE_ICON_PREFIX + this.getPhoto();
        String url = String.format(S3ImageHandler.AMAZON_PROFILE_DOWNLOAD_LINK, photo);
        return url;
    }
}

and then replace the whole if (element.getPhoto() != null) {...} with:

Glide.with(getContext())
     .load(element.getPhotoUrl()) // this may be null --\
     .asBitmap() //                                     |
     .diskCacheStrategy(DiskCacheStrategy.ALL) //       |
     .placeholder(R.drawable.user_small) //             |
     .fallback(R.drawable.user_small) // <--------------/
     .into(new BitmapImageViewTarget(viewHolder.friendIcon) { ... })
;

This will also result in proper behavior because even though there's no image url Glide will take care of setting something, see JavaDoc or source of fallback.

As a sidenote also consider using CircleCrop. Aside from caching benefits it would also support GIFs because you can remove the .asBitmap() and the custom target.

like image 117
TWiStErRob Avatar answered Dec 21 '22 09:12

TWiStErRob