简体   繁体   English

带有排球图像请求(取消请求)的回收者视图

[英]Recycler view with volley image request (cancel request)

So i am using recycler view to show images in a grid and downloading images from url as bitmaps using volley library. 因此,我正在使用回收站视图在网格中显示图像,并使用凌空库从URL下载图像作为位图。

public void onBindViewHolder(final TrendingAdapter.ViewHolder viewHolder, int i) {
    ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap bitmap) {
            if (bitmap != null) {
                viewHolder.getmImageView().setImageBitmap(bitmap);
            }
        }
    }, 0, 0, null,
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError volleyError) {
                }
            });
    AppController.getInstance().addToRequestQueue(request);
}

The problem is when i scroll and skip one or more views before the image is downloaded and that view is recycled the image donwnload reqest is not canceled on those intermediate view resulting in a flash of that/those image(s) before the actual image is loaded in that view. 问题是当我在下载图像之前滚动并跳过一个或多个视图并且该视图被回收时,那些中间视图上的图像下载请求没有被取消,从而导致该/那些图像在实际图像被刷新之前就闪烁了。在该视图中加载。

So i thought of canceling those intermediate image requests using tags but cannot figure out how as it results in canceling of request in other parallel views as well! 所以我想到了使用标签取消这些中间图像请求,但无法弄清楚它如何导致其他并行视图中的请求取消!

Also when i use volley NetworkImageView (that handels such image canceling by itself) gives perfect results. 另外,当我使用截击NetworkImageView时(它本身可以消除此类图像)会给出完美的结果。 But i need to get bitmap of every image to pick colors from it so i cannot use NetworkImageView. 但是我需要获取每个图像的位图以从中选择颜色,因此我无法使用NetworkImageView。

Q) How do i cancel all pending volley image requsts (except the one it should be loading and without effecting other parallel views) on a specific imageview inflated using recyclerview? 问)如何在使用recyclerview放大的特定imageview上取消所有待处理的凌空图像要求(除了它应该加载且不影响其他平行视图的要求)?

You should use the ImageLoader class instead of directly adding a request to the RequestQueue . 您应该使用ImageLoader类,而不是直接向RequestQueue添加RequestQueue That way, the get() method, which is used to get images, will return an object of type ImageContainer . 这样,用于获取图像的get()方法将返回ImageContainer类型的对象。

Save this ImageContainer in the ViewHolder , and when a view gets recycled, simply call the cancelRequest() method on the recycled image to cancel the request if it hasn't been performed yet. 将此ImageContainer保存在ViewHolder ,然后在回收视图时,只需对回收的图像调用cancelRequest()方法即可取消请求(如果尚未执行)。

Take a look at the NetworkImageView 's code. 看一下NetworkImageView的代码。 It works in a similar way. 它以类似的方式工作。

I solved the problem ! 我解决了问题! yaaeeye :D @Itai 's answer pointed me in the correct direction. yaaeeye:D @Itai的答案向正确的方向指出了我。 I took a close look at NetworkImageView code and modified it according to my need. 我仔细研究了NetworkImageView代码,并根据需要对其进行了修改。 So i made a CustumNetworkImageView 所以我做了一个CustumNetworkImageView

public class CustomNetworkImageView extends ImageView {

    // Added code block start

    public interface ResponseObserver {
        public void onError();

        public void onSuccess();
    }

    private ResponseObserver mResponseObserver;

    public void setmResponseObserver(ResponseObserver observer) {
        mResponseObserver = observer;
    }

    private Bitmap bmp = null;

    // Added code block end

    private String mUrl;

    private int mDefaultImageId;

    private int mErrorImageId;

    private ImageLoader mImageLoader;

    public CustomNetworkImageView(Context context) {
        this(context, null);
    }

    public CustomNetworkImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setImageUrl(String url, ImageLoader imageLoader) {
        mUrl = url;
        mImageLoader = imageLoader;
        loadImageIfNecessary();
    }

    public void setDefaultImageResId(int defaultImage) {
        mDefaultImageId = defaultImage;
    }

    public void setErrorImageResId(int errorImage) {
        mErrorImageId = errorImage;

        // Added code block start

        if (mResponseObserver != null) {
            mResponseObserver.onError();
        }

        // Added code block end

    }

    // Added code block start

    public Bitmap getBitmap() {
        return bmp;
    }

    // Added code block end

    private void loadImageIfNecessary() {
        int width = getWidth();
        int height = getHeight();

        if (width == 0 && height == 0) {
            return;
        }

        if (TextUtils.isEmpty(mUrl)) {
            ImageContainer oldContainer = (ImageContainer) getTag();
            if (oldContainer != null) {
                oldContainer.cancelRequest();
                setImageBitmap(null);
            }
            return;
        }

        ImageContainer oldContainer = (ImageContainer) getTag();

        if (oldContainer != null && oldContainer.getRequestUrl() != null) {
            if (oldContainer.getRequestUrl().equals(mUrl)) {

                return;
            } else {

                oldContainer.cancelRequest();
                setImageBitmap(null);
            }
        }

        ImageContainer newContainer = mImageLoader.get(mUrl,
                ImageLoader.getImageListener(this, mDefaultImageId, mErrorImageId));

        setTag(newContainer);

        final Bitmap bitmap = newContainer.getBitmap();
        if (bitmap != null) {

            setImageBitmap(bitmap);

           // Added code block start

            bmp = bitmap;
            if (mResponseObserver != null) {
                mResponseObserver.onSuccess();
            }

           // Added code block end
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        loadImageIfNecessary();
    }

    @Override
    protected void onDetachedFromWindow() {
        ImageContainer oldContainer = (ImageContainer) getTag();
        if (oldContainer != null) {

            oldContainer.cancelRequest();
            setImageBitmap(null);

            setTag(null);
        }
        super.onDetachedFromWindow();
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        invalidate();
    }
}

Using CustomNetworkImageView : 使用CustomNetworkImageView:

    viewHolder.getmImageView().setImageUrl(wallThumb.get(i), AppController.getInstance().getImageLoader());

    viewHolder.getmImageView().setmResponseObserver(new CustomNetworkImageView.ResponseObserver() {

            @Override
            public void onError() {
            }

            @Override
            public void onSuccess() {
                // Image is loaded in ImageView.. Do Something..
                Bitmap bitmap = viewHolder.getmImageView().getBitmap();
            }
        });

SetmResponseObserver listens for if bitmap is loaded in ImageView and onSuccess is called if task is completed.. I also made a fuction that returns the bitmap on the image view and can be used as SetmResponseObserver侦听是否在ImageView中加载了位图,如果任务完成则调用onSuccess。.我还做了一个功能,可以在图像视图上返回位图,并且可以用作

Bitmap bmp = viewHolde.getmImageView.getBitmap();

I am new to android so please feel free to comment and correct me if i have done anything wrong. 我是android新手,所以如果我做错了任何事情,请随时发表评论并纠正我。 Yaaaeeyeee happy dayyy Yaaaeeyeee快乐dayyy

public class RecyclerViewPagerNetworkImageView extends NetworkImageView {
public RecyclerViewPagerNetworkImageView(Context context) {
    super(context);
}

public RecyclerViewPagerNetworkImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public RecyclerViewPagerNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onDetachedFromWindow() {
    // delete
    /*if (mImageContainer != null) {
        // If the view was bound to an image request, cancel it and clear
        // out the image from the view.
        mImageContainer.cancelRequest();
        setImageBitmap(null);
        // also clear out the container so we can reload the image if necessary.
        mImageContainer = null;
    }
    super.onDetachedFromWindow();*/
}

} }

I faced the same problem. 我遇到了同样的问题。 I couldn't use NetworkImageView and image loader because I wanted to have a custom image request. 我无法使用NetworkImageView和图像加载器,因为我想要一个自定义图像请求。

So I found another way to cancel in flight request. 所以我找到了另一种取消飞行请求的方法。 I simply passed the image request in ViewHolder object from onBindViewHolder callback. 我只是通过onBindViewHolder回调在ViewHolder对象中传递了图像请求。 In ViewHolder created a method setRequest(Request request) . ViewHolder创建了一个方法setRequest(Request request)

In this method check if the request is not null then call request.cancel() first otherwise just set the request into the holder. 在此方法中,检查请求是否不为null,然后首先调用request.cancel()否则将请求设置为持有者。

public class ViewHolder extends RecyclerView.ViewHolder {

    public Request request;

    public ViewHolder(View view) {
        super(view);
    }

    public void setRequest(Request request) {
       if (this.request != null) {
            this.request.cancel();
       }
       this.request = request;
    }
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

        ImageRequest imageRequest = new ImageRequest(.......);
        holder.setRequest(request);

        mRequestQueue.add(request);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM