GridView中错误位置的重复项目

时间:2014-12-30 22:53:27

标签: android gridview

我使用UIL将图像从URL加载到Gridview,但问题是图像和项目被复制或加载到许多错误的位置。

离屏幕一半的项目会重复。

enter image description here

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

你能告诉我到目前为止我做错了什么事吗?谢谢。 我在其他地方看到了同样的问题,但他们也没有帮助。

编辑:

我意识到这只会在快速滚动中发生。我该怎么办?

2 个答案:

答案 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);