[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() {@Overridepublic void onErrorResponse(VolleyError error) {if (mErrorImageId != 0) {setImageResource(mErrorImageId);}}@Overridepublic 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() {@Overridepublic 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;">@Overridepublic void onResponse(Bitmap response) {onGetImageSuccess(cacheKey, response);}</span>}, maxWidth, maxHeight,Config.RGB_565, new ErrorListener() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onErrorResponse(VolleyError error) {if (errorImageResId != 0) {view.setImageResource(errorImageResId);}}@Overridepublic void onResponse(ImageContainer response, boolean isImmediate) {if (response.getBitmap() != null) {view.setImageBitmap(response.getBitmap());} else if (defaultImageResId != 0) {view.setImageResource(defaultImageResId);}}};}
版權聲明:本文博客原創文章。博客,未經同意,不得轉載。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[Android]Volley源代码分析(店)应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 被忽视但很实用的那部分SQL
- 下一篇: Android Dialog 系统样式讲