Просмотр ресайклера с запросом изображения залпа (отменить запрос)

Итак, я использую представление recycler для отображения изображений в сетке и загрузки изображений с URL-адреса в виде растровых изображений с использованием библиотеки volley.

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

Проблема заключается в том, что когда я прокручиваю и пропускаю одно или несколько представлений до того, как изображение будет загружено, и это представление будет повторно использовано, запрос на загрузку изображения не отменяется в этих промежуточных представлениях, что приводит к вспышке этого/тех изображений до того, как фактическое изображение будет загружается в этом представлении.

Поэтому я подумал об отмене этих запросов промежуточных изображений с помощью тегов, но не могу понять, как это приводит к отмене запроса и в других параллельных представлениях!

Также, когда я использую залп NetworkImageView (который сам обрабатывает такое отмену изображения), дает отличные результаты. Но мне нужно получить растровое изображение каждого изображения, чтобы выбрать из него цвета, поэтому я не могу использовать NetworkImageView.

В) Как отменить все ожидающие запросы изображений залпа (кроме того, который должен загружаться и не затрагивать другие параллельные представления) для определенного изображения, увеличенного с помощью recyclerview?


person Kushal Sharma    schedule 27.10.2014    source источник
comment
пусть ViewHolder содержит запрос... проверьте, не является ли ViewHolder.request нулевым, и вызовите ViewHolder.request.cancel перед созданием нового запроса...   -  person Selvin    schedule 27.10.2014
comment
вы также можете расширить представление сетевого изображения и, когда получите растровое изображение, использовать его по своему усмотрению.   -  person EC84B4    schedule 27.10.2014
comment
Спасибо ребята! мы прибили это ^.^   -  person Kushal Sharma    schedule 28.10.2014


Ответы (3)


Вы должны использовать класс ImageLoader вместо того, чтобы напрямую добавлять запрос в класс RequestQueue. Таким образом, метод get(), используемый для получения изображений, вернет объект типа ImageContainer.

Сохраните этот ImageContainer в ViewHolder, и когда представление будет переработано, просто вызовите метод cancelRequest() для переработанного изображения, чтобы отменить запрос, если он еще не был выполнен.

Взгляните на код NetworkImageView. Это работает аналогичным образом.

person Itai Hanski    schedule 27.10.2014
comment
Эй, спасибо! вы заставили меня задуматься о правильном пути. Я сделал CustomNetworkImageView и разместил код как ответ. Также, если вы можете мне помочь, я хочу выбрать цвета из растрового изображения. Что было бы лучше? a) getBitmap из imageView, а затем получить цвета b) поместить код для getColors в CustomNetwork... и спросить CustomNetw.. для getColors? - person Kushal Sharma; 28.10.2014
comment
В любом случае должно быть хорошо, посмотрите, что имеет больше смысла для вашего кода. - person Itai Hanski; 28.10.2014

Я решил проблему! yaaeye :D Ответ @Itai указал мне правильное направление. Я внимательно изучил код NetworkImageView и изменил его в соответствии со своими потребностями. Итак, я сделал 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();
    }
}

Использование 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 прослушивает, загружается ли растровое изображение в ImageView, и вызывается onSuccess, если задача завершена. Я также сделал функцию, которая возвращает растровое изображение в представлении изображения и может использоваться как

Bitmap bmp = viewHolde.getmImageView.getBitmap();

Я новичок в Android, поэтому, пожалуйста, не стесняйтесь комментировать и исправлять меня, если я сделал что-то не так. Yaaeeyeee счастливого дня

person Kushal Sharma    schedule 28.10.2014
comment
Что такое getmImageView() ?? - person Umer; 03.11.2015
comment
Привет, @umar, так как я использую шаблон держателя представления с представлением переработчика, getmImageView() - это геттер, который возвращает мне увеличенное представление изображения. В этом случае, поскольку я использую CustomNetworkImageView, getmImageView() возвращает экземпляр того же самого.. - person Kushal Sharma; 03.11.2015

Я столкнулся с той же проблемой. Я не мог использовать NetworkImageView и загрузчик изображений, потому что хотел получить собственный запрос изображения.

Поэтому я нашел другой способ отменить запрос на рейс. Я просто передал запрос изображения в объект ViewHolder из обратного вызова onBindViewHolder. В ViewHolder создал метод setRequest(Request request).

В этом методе проверьте, не является ли запрос нулевым, затем сначала вызовите 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);
}
person Hitesh Gupta    schedule 13.05.2016