我使用UIL将图像从URL加载到Gridview,但问题是图像和项目被复制或加载到许多错误的位置。
离屏幕一半的项目会重复。
这是GridView适配器:
public class GridViewAdapter extends BaseAdapter {
private Activity _activity;
private ArrayList<Object_Wallpaper> wallpapersList;
private ImageLoader mImageLoader;
GridViewAdapter adapter;
ViewHolder holder;
Object_Wallpaper wall;
public GridViewAdapter(Activity activity, ArrayList<Object_Wallpaper> wallpapersList,
int imageWidth) {
this._activity = activity;
this.wallpapersList = new ArrayList<Object_Wallpaper>();
this.wallpapersList = wallpapersList;
this.adapter = this;
this.mImageLoader = ImageLoader.getInstance();
}
@Override
public int getCount() {
return this.wallpapersList.size();
}
@Override
public Object getItem(int position) {
return wallpapersList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/*private view holder class*/
private class ViewHolder {
ImageView smallThumb;
ProgressBar pb;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
holder = new ViewHolder();
if (convertView == null) {
LayoutInflater inflater = _activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.grid_item_photo, null);
holder.smallThumb = (ImageView) convertView.findViewById(R.id.imgThumbnail);
holder.pb = (ProgressBar) convertView.findViewById(R.id.progressBar1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
wall = wallpapersList.get(position);
showImage(position);
return convertView;
}
private void showImage(final int position){
if(!wall.isDownloaded){
mImageLoader.displayImage(wall.smallURL, holder.smallThumb, null,
new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
holder.pb.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
holder.pb.setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
holder.pb.setVisibility(View.GONE);
wall.isDownloaded = true;
wallpapersList.set(position, wall);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
}, new ImageLoadingProgressListener(){
@Override
public void onProgressUpdate(String imageUri, View view,
int current, int total) {
holder.pb.setProgress(Math.round(100.0f * current / total));
}
});
} else {
mImageLoader.displayImage(wall.smallURL, holder.smallThumb);
holder.pb.setVisibility(View.GONE);
}
}
}
这是对象:
public class Object_Wallpaper implements Serializable {
private static final long serialVersionUID = 1L;
public String id,title,tags,fullResURL, thumbURL, smallURL;
public boolean isDownloaded;
public Object_Wallpaper(String id, String title, String tags,
String fullResURL, String thumbURL, String smallURL) {
this.id = id;
this.title = title;
this.tags = tags;
this.fullResURL = fullResURL;
this.thumbURL = thumbURL;
this.smallURL = smallURL;
this.isDownloaded = false;
}
}
你能告诉我到目前为止我做错了什么事吗?谢谢。 我在其他地方看到了同样的问题,但他们也没有帮助。
编辑:
我意识到这只会在快速滚动中发生。我该怎么办?
答案 0 :(得分:2)
问题是您的适配器类有单个字段实例(holder和wall),每次调用getView时都需要这些变量的副本。实际上,当图像加载器完成每个图像时,该图像显示在上次调用的任何项目中。这有意义吗?
第一步是将这些字段更改为getView中的局部变量,将参数更改为showImage。当您向下滚动列表时,在此步骤之后仍然会遇到问题,因为Android会在滚动期间尝试回收您的视图,因此当图像加载程序完成加载图像以查看已滚出视图的位置时,它将会将加载的图像显示在其视图被回收的任何位置。要解决此问题,您可以使用HashMap(或更高效的SparseArray)来跟踪当前哪些回收视图代表哪些位置。
private SparseArray<ViewHolder> holderMap = new SparseArray<ViewHolder>();
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = _activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.grid_item_photo, null);
holder.smallThumb = (ImageView) convertView.findViewById(R.id.imgThumbnail);
holder.pb = (ProgressBar) convertView.findViewById(R.id.progressBar1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
// If recycled, remove the holder's previous position from map
int oldPosition = holderMap.indexOfValue(holder);
if (oldPosition >= 0) {
holderMap.remove(oldPosition);
}
}
// Keep track of which view is representing this position
holderMap.put(position, holder);
Object_Wallpaper wall = wallpapersList.get(position);
showImage(position, holderMap, wall);
return convertView;
}
private void showImage(final int position, final SparseArray<ViewHolder> holderMap, final Object_Wallpaper wall) {
if(!wall.isDownloaded){
mImageLoader.displayImage(wall.smallURL, holder.smallThumb, null,
new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
ViewHolder holder = holderMap.get(position);
if (holder != null) {
holder.pb.setVisibility(View.VISIBLE);
}
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
ViewHolder holder = holderMap.get(position);
if (holder != null) {
holder.pb.setVisibility(View.GONE);
}
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
ViewHolder holder = holderMap.get(position);
if (holder != null) {
holder.pb.setVisibility(View.GONE);
wall.isDownloaded = true;
wallpapersList.set(position, wall);
}
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
}, new ImageLoadingProgressListener(){
@Override
public void onProgressUpdate(String imageUri, View view,
int current, int total) {
ViewHolder holder = holderMap.get(position);
if (holder != null) {
holder.pb.setProgress(Math.round(100.0f * current / total));
}
}
});
} else {
mImageLoader.displayImage(wall.smallURL, holder.smallThumb);
holder.pb.setVisibility(View.GONE);
}
}
编辑:请参阅我之前对类似问题的回答(我使用的是一个名为ivMap的SparseArray - 当键为int时,它比HashMap稍好一些)。
Android BaseAdapter With LruCache Some ui problems
第二次编辑:使用改编的地图解决方案修改代码。
答案 1 :(得分:0)
Java在分配对象时是传递引用。
在getView
方法中,您要为先前对象的相同指针指定新值:
wall = wallpapersList.get(position);
您应该每次都创建新实例。它应该改为:
wall = new Object_Wallpaper();
wall = wallpapersList.get(position);