How to get finish callback on setImageUrl with Volley library and NetworkImageView?

前端 未结 7 1344
萌比男神i
萌比男神i 2020-12-14 01:18

I\'m trying out the Google\'s new Volley library and it\'s looking sharp and loads images quickly when I use this method setImageUrl:

holder.ima         


        
相关标签:
7条回答
  • 2020-12-14 01:38

    Another approach (similar to the code from @Simulant above) is to use use a regular ImageView in your xml and then make the image request using Volley.ImageRequest. If you use the Singleton pattern that is recommended by Google it would look something like this:

    ImageView mImageView = (ImageView) findViewById(R.id.myimageview);
    RequestQueue requestQueue = MyVolleySingleton.getInstance(mContext).getRequestQueue();
    ImageRequest mainImageRequest = new ImageRequest(myImageURL,
        new Response.Listener<Bitmap>() {
           @Override
           public void onResponse(Bitmap bitmap) {
              // set the image here
              mImageView.setImageBitmap(bitmap);
              // hide the spinner here
           }
        }, 0, 0, null, null);
    
     requestQueue.add(mainImageRequest);
    

    By the way: Make sure that you use a regular ImageView instead of the NetworkImageView or the image will not show properly.

    0 讨论(0)
  • 2020-12-14 01:45

    You can use this View instead of Google's View (I've copied sources from it and made some changes):

    public class VolleyImageView extends ImageView {
    
        public interface ResponseObserver
        {
            public void onError();
            public void onSuccess();
        }
    
        private ResponseObserver mObserver;
    
        public void setResponseObserver(ResponseObserver observer) {
            mObserver = observer;
        }
    
        /**
         * The URL of the network image to load
         */
        private String mUrl;
    
        /**
         * Resource ID of the image to be used as a placeholder until the network image is loaded.
         */
        private int mDefaultImageId;
    
        /**
         * Resource ID of the image to be used if the network response fails.
         */
        private int mErrorImageId;
    
        /**
         * Local copy of the ImageLoader.
         */
        private ImageLoader mImageLoader;
    
        /**
         * Current ImageContainer. (either in-flight or finished)
         */
        private ImageContainer mImageContainer;
    
        public VolleyImageView(Context context) {
            this(context, null);
        }
    
        public VolleyImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public VolleyImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        /**
         * Sets URL of the image that should be loaded into this view. Note that calling this will
         * immediately either set the cached image (if available) or the default image specified by
         * {@link VolleyImageView#setDefaultImageResId(int)} on the view.
         *
         * NOTE: If applicable, {@link VolleyImageView#setDefaultImageResId(int)} and {@link
         * VolleyImageView#setErrorImageResId(int)} should be called prior to calling this function.
         *
         * @param url         The URL that should be loaded into this ImageView.
         * @param imageLoader ImageLoader that will be used to make the request.
         */
        public void setImageUrl(String url, ImageLoader imageLoader) {
            mUrl = url;
            mImageLoader = imageLoader;
            // The URL has potentially changed. See if we need to load it.
            loadImageIfNecessary(false);
        }
    
        /**
         * Sets the default image resource ID to be used for this view until the attempt to load it
         * completes.
         */
        public void setDefaultImageResId(int defaultImage) {
            mDefaultImageId = defaultImage;
        }
    
        /**
         * Sets the error image resource ID to be used for this view in the event that the image
         * requested fails to load.
         */
        public void setErrorImageResId(int errorImage) {
            mErrorImageId = errorImage;
        }
    
        /**
         * Loads the image for the view if it isn't already loaded.
         *
         * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
         */
        private void loadImageIfNecessary(final boolean isInLayoutPass) {
            int width = getWidth();
            int height = getHeight();
    
            boolean isFullyWrapContent = getLayoutParams() != null
                    && getLayoutParams().height == LayoutParams.WRAP_CONTENT
                    && getLayoutParams().width == LayoutParams.WRAP_CONTENT;
            // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
            // view, hold off on loading the image.
            if (width == 0 && height == 0 && !isFullyWrapContent) {
                return;
            }
    
            // if the URL to be loaded in this view is empty, cancel any old requests and clear the
            // currently loaded image.
            if (TextUtils.isEmpty(mUrl)) {
                if (mImageContainer != null) {
                    mImageContainer.cancelRequest();
                    mImageContainer = null;
                }
                setDefaultImageOrNull();
                return;
            }
    
            // if there was an old request in this view, check if it needs to be canceled.
            if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
                if (mImageContainer.getRequestUrl().equals(mUrl)) {
                    // if the request is from the same URL, return.
                    return;
                } else {
                    // if there is a pre-existing request, cancel it if it's fetching a different URL.
                    mImageContainer.cancelRequest();
                    setDefaultImageOrNull();
                }
            }
    
            // The pre-existing content of this view didn't match the current URL. Load the new image
            // from the network.
            ImageContainer newContainer = mImageLoader.get(mUrl,
                    new ImageListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            if (mErrorImageId != 0) {
                                setImageResource(mErrorImageId);
                            }
    
                            if(mObserver!=null)
                            {
                                mObserver.onError();
                            }
                        }
    
                        @Override
                        public void onResponse(final ImageContainer response, boolean isImmediate) {
                            // If this was an immediate response that was delivered inside of a layout
                            // pass do not set the image immediately as it will trigger a requestLayout
                            // inside of a layout. Instead, defer setting the image by posting back to
                            // the main thread.
                            if (isImmediate && isInLayoutPass) {
                                post(new Runnable() {
                                    @Override
                                    public void run() {
                                        onResponse(response, false);
                                    }
                                });
                                return;
                            }
    
                            if (response.getBitmap() != null) {
                                setImageBitmap(response.getBitmap());
                            } else if (mDefaultImageId != 0) {
                                setImageResource(mDefaultImageId);
                            }
    
                            if(mObserver!=null)
                            {
                                mObserver.onSuccess();
                            }
                        }
                    });
    
            // update the ImageContainer to be the new bitmap container.
            mImageContainer = newContainer;
        }
    
        private void setDefaultImageOrNull() {
            if (mDefaultImageId != 0) {
                setImageResource(mDefaultImageId);
            } else {
                setImageBitmap(null);
            }
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            loadImageIfNecessary(true);
        }
    
        @Override
        protected void onDetachedFromWindow() {
            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();
        }
    
        @Override
        protected void drawableStateChanged() {
            super.drawableStateChanged();
            invalidate();
        }
    }
    

    Usage example :

     //set observer to view
     holder.image.setResponseObserver(new VolleyImageView.ResponseObserver() {
         @Override
         public void onError() {
    
         }
    
         @Override
         public void onSuccess() {
    
         }
     });
    
    //and then load image
    holder.image.setImageUrl(url, ImageCacheManager.getInstance().getImageLoader());
    
    0 讨论(0)
  • 2020-12-14 01:47

    Step 1: Declare imageLoader, (i have a MySocialMediaSingleton class for manage the Volley Request)

    ImageLoader imageLoader = MySocialMediaSingleton.getInstance(context).getImageLoader();
    

    Step 2: use the callback for imageLoader

    imageLoader.get(url, new ImageLoader.ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                 //an error ocurred
            }
    
            @Override
            public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
                if (response.getBitmap() != null) {
                    //loadingView gone
                } else {
                    //some code
                }
            }
        });
    

    Step 3: Show the response in you imageView or NetworkImageView

    holder.image.setImageUrl(ImageCacheManager.getInstance().getImageLoader(), imageLoader);
    
    0 讨论(0)
  • 2020-12-14 01:48

    I did it this way:-

    mImageLoader.get(url, new ImageLoader.ImageListener() {
        @Override
        public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
            if (response.getBitmap() != null)
                //some code
            else
                //some code
        }
        @Override
        public void onErrorResponse(VolleyError error) {
        }
    });
    
    0 讨论(0)
  • 2020-12-14 01:49

    Yet another approach, that relies on knowing the internals of NetworkImageView, is to subclass NetworkImageView to watch for the mErrorImageId getting applied.

    public class ManagedNetworkImageView extends NetworkImageView{
        private int mErrorResId;
    
        public ManagedNetworkImageView(Context context) {
            super(context);
        }
    
        public ManagedNetworkImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public ManagedNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public void setErrorImageResId(int errorImage) {
            mErrorResId = errorImage;
            super.setErrorImageResId(errorImage);
        }
    
        @Override
        public void setImageResource(int resId) {
            if (resId == mErrorResId) {
                // TODO Handle the error here
            }
            super.setImageResource(resId);
        }
    
        @Override
        public void setImageBitmap(Bitmap bm) {
            // TODO Handle the success here
            super.setImageBitmap(bm);
        }
    }
    

    You'll also have to replace NetworkImageView with ManagedNetworkImageView in your layout files.

    It's a bit hacky, but does the job when NetworkImageView is already your chosen solution.

    0 讨论(0)
  • 2020-12-14 01:50
    Listener<Bitmap> imageListener = new Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            //This call back method is executed in the UI-Thread, when the loading is finished
            imageView.setImageBitmap(response); //example
        }
    };
    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
          //log your error
        }
    };
    //url, ListenerOnFinish, width, height, errorListener
    ImageRequest getImageRequest = new ImageRequest(url, imageListener, 0, 0, null,errorListener);
    requestQueue.add(getImageRequest);
    
    0 讨论(0)
提交回复
热议问题