3

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

3 回答 3

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 周期。这留给读者作为练习。

于 2012-08-05T06:31:05.413 回答
0

我的GridView. 虽然项目不多,只有 24 个,而且我从手机的 SD 卡而不是在线加载图像,但当我滚动时,我仍然得到图像四处跳动,这实际上只有一两行隐藏在视图之外时间。

我所做的只是简单地添加一个ViewHolder并且它是固定的。看起来本教程的实现方式与@scompt.com 类似。他在教程中的观点是,通过ViewHolder这样的方式,findViewById()当视图被回收时,不会重复调用 to。这可能是滚动时图像不再跳跃的原因。

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

在我的适配器类中: 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;
    }
于 2015-03-23T00:07:15.540 回答
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);
        }
    });

使用排球:

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

image.setImageUrl(url, mImageLoader);
于 2014-02-21T14:40:18.713 回答