[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 系统样式讲