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()
和自定义目标。
我正在开发 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()
和自定义目标。