Android 带有 Glide 的列表视图 - 加载后双倍位图

Android listview with Glide - doubled bitmaps after load

我正在开发 android 应用程序。我的一个片段包含一个显示好友列表的简单列表视图。每个朋友都可以有自己的头像——它由 Glide 库设置。当用户没有设置个人资料图片时,将显示默认图像。我的问题是,每次,列表中的第一个元素都会得到相同的图片,该图片设置在列表的最后一个元素上,而不是默认图片。我的意思如图所示:

名称为 wiktor 的用户设置了头像,如您所见,第一个位置 bonzo 有 wiktor 的头像(bonzo 应该是默认的图片 )

删除用户表单列表也有问题:

如你所见,我从朋友列表中删除了 majka,下一个元素是她的照片。

默认个人资料图片设置在 drawables 的内行布局 xml 中。

这是我的列表视图适配器的代码:

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

正在从好友列表中删除用户:

        remove(element);
        notifyDataSetChanged();

你们有没有看到我做错了什么?如果能提供一些帮助,我将不胜感激。谢谢:)

您正在重新处理列表项(根据回收站视图的定义),这意味着如果图像已设置到某个项目而您没有清除它,图像将保留在那里。所以即使 setText 改变了标签 viewHolder.friendIcon 也没有被触及。修复非常简单:

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
}

同时从 xml 中删除 drawable,或者至少更改为 tools:src 这将有助于减少 inflation 时间;无论如何,该值每次都会被 Glide 覆盖。


为了降低复杂性,还有一个替代方案:

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

然后将整个 if (element.getPhoto() != null) {...} 替换为:

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

这也会导致正确的行为,因为即使没有图像 url Glide 也会负责设置一些东西,请参阅 JavaDoc 或 fallback 的来源。

作为旁注,也可以考虑使用 CircleCrop。除了缓存优势外,它还支持 GIF,因为您可以删除 .asBitmap() 和自定义目标。