• [Android]Volley源代码分析(店)应用


    通过前面的谈话,我相信你有Volley有了一定的了解了原理。本章将给出一些我们的应用程序都可以在样品中直接使用,第一样品是

    NetworkImageView类,事实上NetworkImageView顾名思义就是将异步的操作封装在了控件本身,这样的设计能够充分保留控件的移植性和维护性。

    NetworkImageView通过调用setImageUrl来指定详细的url:

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

    void loadImageIfNecessary(final boolean isInLayoutPass) {
            int width = getWidth();
            int height = getHeight();
    
            boolean wrapWidth = false, wrapHeight = false;
            if (getLayoutParams() != null) {
                wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
                wrapHeight = getLayoutParams().height == 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.
            boolean isFullyWrapContent = wrapWidth && wrapHeight;
            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();
                }
            }
    
            // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
            int maxWidth = wrapWidth ?

    0 : width; int maxHeight = wrapHeight ?

    0 : height; // 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); } } @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); } } }, maxWidth, maxHeight); // update the ImageContainer to be the new bitmap container. mImageContainer = newContainer; }


    我们从这段逻辑不难看出,url这个属性的持有者是ImageContainer.当Bitmap相应的url与Container相应的url同样的时候,Volley将直接返回。

    否则将通过一个叫做ImageLoader的对象get.

    ImageContainer newContainer = mImageLoader.get(mUrl,
                    new ImageListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            if (mErrorImageId != 0) {
                                setImageResource(mErrorImageId);
                            }
                        }
    
                        @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);
                            }
                        }
                    }, maxWidth, maxHeight);
    ImageLoader.get(String requestUrl, ImageListener imageListener,
                int maxWidth, int maxHeight):

    public ImageContainer get(String requestUrl, ImageListener imageListener,
                int maxWidth, int maxHeight) {
            // only fulfill requests that were initiated from the main thread.
            throwIfNotOnMainThread();
    
            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>() {
                    <span style="color:#009900;">@Override
                    public void onResponse(Bitmap response) {
                        onGetImageSuccess(cacheKey, response);
                    }</span>
                }, 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;
        }
          ImageLoader開始的第一步你可能非常难理解,为什么须要自己从Cache中获得?RequestQueue不是都已经帮你做好了这些么?实际上这个Cache是NetworkImageView 自己定义的Cache:ImageCache。而这样的Cache被Volley抛给用户去实现,你能够通过适配器模式装饰成为你自己的Cache,也能够装饰成DiskBaseCache。

          通过绿色段代码我们能够知道当ImageLoader在Volley返回的时候回调 onGetImageSuccess(cacheKey, response)方法。

    这种方法是为了补充回调ImageLoader自定义的ImageListener回调

    private void batchResponse(String cacheKey, BatchedImageRequest request) {
            mBatchedResponses.put(cacheKey, request);
            // If we don't already have a batch delivery runnable in flight, make a new one.
            // Note that this will be used to deliver responses to all callers in mBatchedResponses.
            if (mRunnable == null) {
                mRunnable = new Runnable() {
                    @Override
                    public void run() {
                        for (BatchedImageRequest bir : mBatchedResponses.values()) {
                            for (ImageContainer container : bir.mContainers) {
                                // If one of the callers in the batched request canceled the request
                                // after the response was received but before it was delivered,
                                // skip them.
                                if (container.mListener == null) {
                                    continue;
                                }
                                if (bir.getError() == null) {
                                    container.mBitmap = bir.mResponseBitmap;
                                    container.mListener.onResponse(container, false);
                                } else {
                                    container.mListener.onErrorResponse(bir.getError());
                                }
                            }
                        }
                        mBatchedResponses.clear();
                        mRunnable = null;
                    }
    
                };
                // Post the runnable.
                mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);
            }
        }

    能够看到,这一切的命令都发生在UI线程中。最后通过ImageListener回调来实现图片设置。

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





    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    嵌入式:指针的指针、链表、UCOS 的 OSMemCreate 。
    嵌入式&iOS:回调函数(C)与block(OC)传 参/函数 对比
    嵌入式&iOS:回调函数(C)与block(OC)回调对比
    iOS:以前笔记,未整理版。太多了,先放着吧。。。。。。。
    嵌入式:小技巧(慢慢回忆更新)(16.12.17更)
    嵌入式:J-link刷固件(坑)
    iOS:GCD组
    Android Studio教程07-Fragment的使用
    Android Studio教程06-布局,监听器以及基本控件
    Android Studio教程05-Parcelables和Bundles.md
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4687509.html
Copyright © 2020-2023  润新知