滚动gridview时图像更改

时间:2012-08-05 05:16:57

标签: android android-asynctask

GridView从URL加载图片。当我滚动gridview,更多的图像机会,如何解决它...我尝试过imageAdapter.notifyDataSetChanged(),gridView.invalidateViews()..我还没有找到解决这个问题的方法。

public class ImageAdapter extends BaseAdapter{

    private Context mContext;
    private LayoutInflater mInflater;   
    private ArrayList<NodeFood> listImage = new ArrayList<NodeFood>();

    public ImageAdapter(Context c, ArrayList<NodeFood> listImage){
        this.mContext = c;
        this.listImage = listImage;
    }

    public class ViewHolder{
        ImageView imageView;
        ProgressBar progress;
    }

    public int getCount() {
        return listImage.size();
    }

    public Object getItem(int arg0) {
        return arg0;
    }

    public long getItemId(int arg0) {
        return arg0;
    }

    public View getView(int arg0, View arg1, ViewGroup arg2) {
        final ViewHolder holder;
        if(arg1 == null){
            holder  = new ViewHolder();
            mInflater = LayoutInflater.from(mContext);
            arg1    =   mInflater.inflate(R.layout.layout_item_grid, null);
            holder.imageView = (ImageView)arg1.findViewById(R.id.imageItemGrid);
            holder.progress = (ProgressBar)arg1.findViewById(R.id.progressBar);
            holder.progress.getIndeterminateDrawable().setColorFilter(0xFFFF0000,android.graphics.PorterDuff.Mode.MULTIPLY);
            arg1.setTag(holder);
        }else{
            holder = (ViewHolder)arg1.getTag();
        }
        holder.imageView.setTag(arg0);
        holder.progress.setTag(arg0);
        NodeFood a = this.listImage.get(arg0);
        String URL = a.getSRC();
        task_LoadIMG bb = new task_LoadIMG(URL,holder);
        bb.execute();
        return arg1;
    }   

    public class task_LoadIMG extends AsyncTask<Void,Void,Bitmap>{
        private String url;
        private ViewHolder holder;
        public task_LoadIMG(String url, ViewHolder holder){
            this.url = url;
            this.holder = holder;
        }
        @Override
        protected Bitmap doInBackground(Void... arg0) {
            try{
                URL aURL = new URL(this.url);
                URLConnection connect = aURL.openConnection();
                connect.connect();

                InputStream is = connect.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(is);
                Bitmap bm = BitmapFactory.decodeStream(bis);
                bis.close();
                is.close();
                return bm;
            }catch(IOException e){
                return null;
            }
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            holder.progress.setVisibility(View.GONE);
            holder.imageView.setImageBitmap(result);
            holder.imageView.setScaleType(ScaleType.CENTER_CROP);
        }
    }
}

3 个答案:

答案 0 :(得分:3)

问题是您的AsyncTask加载图片的时间比显示的图片要长。一旦完成下载,该单元格已经过去了,并且已经被回收用于下一张图像。

要解决此问题,请将单元格图像的URL存储在单元格的tag属性中。然后,检查以确保AsyncTask完成时单元格URL相同。如果它不相同,那么单元格在此期间已被回收,您应该放弃更新。这是一些代码:

public View getView(int arg0, View arg1, ViewGroup arg2) {
    final ViewHolder holder;
    if(arg1 == null){
        holder  = new ViewHolder();
        mInflater = LayoutInflater.from(mContext);
        arg1    =   mInflater.inflate(R.layout.layout_item_grid, null);
        holder.imageView = (ImageView)arg1.findViewById(R.id.imageItemGrid);
        holder.progress = (ProgressBar)arg1.findViewById(R.id.progressBar);
        holder.progress.getIndeterminateDrawable().setColorFilter(0xFFFF0000,android.graphics.PorterDuff.Mode.MULTIPLY);
        arg1.setTag(holder);
    }else{
        holder = (ViewHolder)arg1.getTag();
    }
    NodeFood a = this.listImage.get(arg0);
    String URL = a.getSRC();
    holder.imageView.setTag(URL);
    task_LoadIMG bb = new task_LoadIMG(URL,holder);
    bb.execute();
    return arg1;
}   

public class task_LoadIMG extends AsyncTask<Void,Void,Bitmap>{
    private String url;
    private ViewHolder holder;
    public task_LoadIMG(String url, ViewHolder holder){
        this.url = url;
        this.holder = holder;
    }
    @Override
    protected Bitmap doInBackground(Void... arg0) {
        try{
            URL aURL = new URL(this.url);
            URLConnection connect = aURL.openConnection();
            connect.connect();

            InputStream is = connect.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is);
            Bitmap bm = BitmapFactory.decodeStream(bis);
            bis.close();
            is.close();
            return bm;
        }catch(IOException e){
            return null;
        }
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        if (url.equals(holder.imageView.getTag()) {
            holder.progress.setVisibility(View.GONE);
            holder.imageView.setImageBitmap(result);
            holder.imageView.setScaleType(ScaleType.CENTER_CROP);
        } else {
            // View was updated in the meantime, ignore the image
        }
    }
}

您可能还会考虑在单元格被回收后立即取消AsyncTask以节省带宽/ CPU周期。这是留给读者的练习。

答案 1 :(得分:0)

我使用排球,你可以摆脱所有异步任务,标签......

使用com.android.volley.toolbox.NetworkImageView重新使用ImageView

类似的东西:

<com.android.volley.toolbox.NetworkImageView
android:id="@+id/twitter_avatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_marginRight="6dip"/>


private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;

private LruCache<String, Bitmap> mMemoryCache;

然后:

final int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = 1024 * 1024 * memClass / 8;
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in bytes rather than number of items.
            return bitmap.getByteCount();
        }

    };

    mRequestQueue = Volley.newRequestQueue(context);
    mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {

        public void putBitmap(String url, Bitmap bitmap) {
            mMemoryCache.put(url, bitmap);
        }

        public Bitmap getBitmap(String url) {
            return mMemoryCache.get(url);
        }
    });

使用Volley:

NetworkImageView image = (NetworkImageView) row.findViewById(R.id.ivGridViewImage);

image.setImageUrl(url, mImageLoader);

答案 2 :(得分:0)

我的GridView遇到了同样的问题。虽然没有多少项目,只有24,我从手机的SD卡而不是在线加载图像,当我滚动时,我仍然得到图像四处跳跃,这实际上只是一两行被隐藏从一次来看。

我所做的只是添加一个ViewHolder并修复了。看起来这个tutorial与@ scompt.com类似地实现它。他在本教程中的观点是,对于这样的ViewHolder,当视图被回收时,不会重复调用findViewById()。这可能就是为什么图像在滚动时不再跳转的原因。

不确定这是否会帮助处于同样困境的其他人。我搜索了S.O.对于这个问题,很少有人解决它。希望它可以帮到某人。

在我的适配器类中: PhotoGridItem是我的模型类,在我的ArrayAdapter扩展名中输入,如下所示:ArrayAdapter<PhotoGridItem>。只是为了解释我的代码。

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

        View row = convertView;
        final ViewHolder holder;

        if (row == null) {

            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(resourceId, parent, false);

            holder = new ViewHolder();
            holder.imageView = (ImageView) row.findViewById(R.id.photo_grid_view);
            // stores holder with view
            row.setTag(holder);

        } else {

            holder = (ViewHolder)convertView.getTag();
        }

        PhotoGridItem photoGridItem = getItem(position);

        if (photoGridItem != null) {
            bm = photoGridItem.getImage();
            holder.imageView.setImageBitmap(bm);

            // positioning the image in the GridView slot
            holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            holder.imageView.setLayoutParams(new LinearLayout.LayoutParams
                    (270, 270));
        }

        return row;

    }

    public class ViewHolder{
        ImageView imageView;
    }