Android:Volley: Why volley imageLoader must be invoked from the main thread?
Asked Answered
H

1

7

My code is:

class MyService extends Service{
    public void onCreate(){
          new ImageLoader(mRequestQueue, new VolleyLruCache(cacheSize))
                                            .get(url, new ImageListener(){..});
    }
}

I expect working well, but it throw IllegalStateException Exception. So, open the volley full source, find this.

[ImageLoader.java]

    public ImageContainer get(String requestUrl, ImageListener imageListener,
        int maxWidth, int maxHeight) {
    // only fulfill requests that were initiated from the main thread.
    throwIfNotOnMainThread();   //<- why???

    final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);

    // Try to look up the request in the cache of remote images.
    Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
    if (cachedBitmap != null) {
        // Return the cached bitmap.
        ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
        imageListener.onResponse(container, true);
        return container;
    }

    // The bitmap did not exist in the cache, fetch it!
    ImageContainer imageContainer =
            new ImageContainer(null, requestUrl, cacheKey, imageListener);

    // Update the caller to let them know that they should use the default bitmap.
    imageListener.onResponse(imageContainer, true);

    // Check to see if a request is already in-flight.
    BatchedImageRequest request = mInFlightRequests.get(cacheKey);
    if (request != null) {
        // If it is, add this request to the list of listeners.
        request.addContainer(imageContainer);
        return imageContainer;
    }

    // The request is not already in flight. Send the new request to the network and
    // track it.
    Request<?> newRequest =
        new ImageRequest(requestUrl, new Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                onGetImageSuccess(cacheKey, response);
            }
        }, maxWidth, maxHeight,
        Config.RGB_565, new ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                onGetImageError(cacheKey, error);
            }
        });

    mRequestQueue.add(newRequest);
    mInFlightRequests.put(cacheKey,
            new BatchedImageRequest(newRequest, imageContainer));
    return imageContainer;
}

I don't understand throwIfNotOnMainThread().. Why volley imageLoader must be invoked from the main thread?

Thanks.

Hafer answered 7/5, 2014 at 8:33 Comment(1)
java.lang.IllegalStateException: ImageLoader must be invoked from the main thread. at com.android.volley.toolbox.ImageLoader.throwIfNotOnMainThread(ImageLoader.java:467) at com.android.volley.toolbox.ImageLoader.get(ImageLoader.java:189) at com.android.volley.toolbox.ImageLoader.get(ImageLoader.java:171) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.os.HandlerThread.run(HandlerThread.java:61)Hafer
D
2

It is to guarantee that the response callback happens on the main UI thread assuming that the callback would want to update the UI.

The default implementation of ImageListener provided by Volley library updates the UI and hence it has to be used from main thread.

   /**
     * The default implementation of ImageListener which handles basic functionality
     * of showing a default image until the network response is received, at which point
     * it will switch to either the actual image or the error image.
     * @param imageView The imageView that the listener is associated with.
     * @param defaultImageResId Default image resource ID to use, or 0 if it doesn't exist.
     * @param errorImageResId Error image resource ID to use, or 0 if it doesn't exist.
     */
    public static ImageListener getImageListener(final ImageView view,
            final int defaultImageResId, final int errorImageResId) {
        return new ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (errorImageResId != 0) {
                    view.setImageResource(errorImageResId);
                }
            }
            @Override
            public void onResponse(ImageContainer response, boolean isImmediate) {
                if (response.getBitmap() != null) {
                    view.setImageBitmap(response.getBitmap());
                } else if (defaultImageResId != 0) {
                    view.setImageResource(defaultImageResId);
                }
            }
        };
    }
Decoration answered 7/5, 2014 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.