Picasso源码完全解析(五)--图片的获取(BitmapHunter)
来源:互联网 发布:2016开淘宝店晚不晚 编辑:程序博客网 时间:2024/05/01 21:35
Picasso源码完全解析(一)--概述
Picasso源码完全解析(二)--Picasso实例的创建
Picasso源码完全解析(三)--Request和Action的创建
Picasso源码完全解析(四)--Action分发和执行
Picasso源码完全解析(五)--图片的获取(BitmapHunter)
Picasso源码完全解析(六)--请求的取消、暂停、和恢复
Picasso源码完全解析(七)-- CleanupThread 取消请求
Picasso源码完全解析(五)--图片的获取(BitmapHunter)
从上一节的分析可以知道,最终的Action是由dispatcher.performSubmit(action)执行的,看看这个方法的源码:
void performSubmit(Action action) { performSubmit(action, true);}void performSubmit(Action action, boolean dismissFailed) { if (pausedTags.contains(action.getTag())) { pausedActions.put(action.getTarget(), action); if (action.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(), "because tag '" + action.getTag() + "' is paused"); } return; } BitmapHunter hunter = hunterMap.get(action.getKey()); if (hunter != null) { hunter.attach(action); return; } if (service.isShutdown()) { if (action.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down"); } return; } hunter = forRequest(action.getPicasso(), this, cache, stats, action); hunter.future = service.submit(hunter); hunterMap.put(action.getKey(), hunter); if (dismissFailed) { failedActions.remove(action.getTarget()); } if (action.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId()); }}
上面的代码的逻辑很清晰,首先根据Action的Tag判断该Action是否应该被暂停,如果是则把该Action添加到暂停的Action的Map集合里然后返回;否则在已有的hunter中查找该Action对应的Hunter,如果存在直接使用该Hunter的结果。否则,这个Action是一个新的请求,首先通过forRequest()创建该Action的BitMapHunter,然后将该Hunter提交到线程池上执行,同时将该Hunter加入Hunter Map集合。至此,我们终于看见任务被提交到线程池上了。
BitMapHunter是如何创建的----职责链模式
首先我们来看看forRequest()的源码:
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action) { Request request = action.getRequest(); List<RequestHandler> requestHandlers = picasso.getRequestHandlers(); // Index-based loop to avoid allocating an iterator. //noinspection ForLoopReplaceableByForEach for (int i = 0, count = requestHandlers.size(); i < count; i++) { RequestHandler requestHandler = requestHandlers.get(i); if (requestHandler.canHandleRequest(request)) { return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler); } } return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);}
我们可以看到,首先从Action里取出其对应的Request,然后从Picasso里取出RequestHandler列表,遍历这个列表,找出能够处理该Request的handler并创建BitmapHunter,如果找不到,创建默认的BitmapHunter,这是一个典型的职责链模式。
那么,职责链是如何创建的,我们看看Picasso的构造函数:
int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0); List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount); // ResourceRequestHandler needs to be the first in the list to avoid // forcing other RequestHandlers to perform null checks on request.uri // to cover the (request.resourceId != 0) case. allRequestHandlers.add(new ResourceRequestHandler(context)); if (extraRequestHandlers != null) { allRequestHandlers.addAll(extraRequestHandlers); } allRequestHandlers.add(new ContactsPhotoRequestHandler(context)); allRequestHandlers.add(new MediaStoreRequestHandler(context)); allRequestHandlers.add(new ContentStreamRequestHandler(context)); allRequestHandlers.add(new AssetRequestHandler(context)); allRequestHandlers.add(new FileRequestHandler(context)); allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats)); requestHandlers = Collections.unmodifiableList(allRequestHandlers);
上面这段代码可以看出,首先在RequestHandler列表里加入ResourceRequestHandler,用于处理资源请求,其次加入调用者自己加入的RequestHandler,最后加入Picasso默认的RequestHandler。这样,职责链就在Picasso创建的时候建立了。同时,我们应该注意到,当我们有新的图片处理逻辑的时候,可以通过增加RequestHandler来扩展我们的需求,只需要继承RequestHandler,实现其
public abstract boolean canHandleRequest(Request data);public abstract Result load(Request request, int networkPolicy) throws IOException;
方法,同时将RequestHandler实例在Picasso初始化的时候注入进去就可以了。这也体现了面向接口编程的思想。
BitMap是如何获取的
hunter.future = service.submit(hunter);
从这段代码我们可以看到Hunter最终被提交到线程池上执行。
class BitmapHunter implements Runnable
BitmapHunter其实是一个Runnable,是对请求任务的封装,所以,在线程池上执行的是其run()方法,源码如下:
@Overridepublic void run() { try { updateThreadName(data); if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this)); } result = hunt(); if (result == null) { dispatcher.dispatchFailed(this); } else { dispatcher.dispatchComplete(this); } } catch (NetworkRequestHandler.ResponseException e) { if (!NetworkPolicy.isOfflineOnly(e.networkPolicy) || e.code != 504) { exception = e; } dispatcher.dispatchFailed(this); } catch (IOException e) { exception = e; dispatcher.dispatchRetry(this); } catch (OutOfMemoryError e) { StringWriter writer = new StringWriter(); stats.createSnapshot().dump(new PrintWriter(writer)); exception = new RuntimeException(writer.toString(), e); dispatcher.dispatchFailed(this); } catch (Exception e) { exception = e; dispatcher.dispatchFailed(this); } finally { Thread.currentThread().setName(Utils.THREAD_IDLE_NAME); }}
代码很清晰,通过hunt()方法,获得Bitmap,然后将结果通过Dispatcher进行分发处理,原理如前面章节所述。
BitMap的获取主要在hunt()里,源码如下:
Bitmap hunt() throws IOException { Bitmap bitmap = null; if (shouldReadFromMemoryCache(memoryPolicy)) { bitmap = cache.get(key); if (bitmap != null) { stats.dispatchCacheHit(); loadedFrom = MEMORY; if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache"); } return bitmap; } } networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy; RequestHandler.Result result = requestHandler.load(data, networkPolicy); if (result != null) { loadedFrom = result.getLoadedFrom(); exifOrientation = result.getExifOrientation(); bitmap = result.getBitmap(); // If there was no Bitmap then we need to decode it from the stream. if (bitmap == null) { Source source = result.getSource(); try { bitmap = decodeStream(source, data); } finally { try { //noinspection ConstantConditions If bitmap is null then source is guranteed non-null. source.close(); } catch (IOException ignored) { } } } } if (bitmap != null) { if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_DECODED, data.logId()); } stats.dispatchBitmapDecoded(bitmap); if (data.needsTransformation() || exifOrientation != 0) { synchronized (DECODE_LOCK) { if (data.needsMatrixTransform() || exifOrientation != 0) { bitmap = transformResult(data, bitmap, exifOrientation); if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId()); } } if (data.hasCustomTransformations()) { bitmap = applyCustomTransformations(data.transformations, bitmap); if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations"); } } } if (bitmap != null) { stats.dispatchBitmapTransformed(bitmap); } } } return bitmap;}
最关键的是这句代码:
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
由此可见,Bitmap最终是由BitmapHunter的requestHandler.load()方法获取的。
Picasso默认提供了ResourceRequestHandler、ContactsPhotoRequestHandler、MediaStoreRequestHandler、ContentStreamRequestHandler、 AssetRequestHandler、FileRequestHandler、NetworkRequestHandler等7中RequestHandler,用来从不同的来源获取Bitmap,下面重点分析NetworkRequestHandler的实现。
@Overridepublic Result load(Request request, int networkPolicy) throws IOException { okhttp3.Request downloaderRequest = createRequest(request, networkPolicy); Response response = downloader.load(downloaderRequest); ResponseBody body = response.body(); if (!response.isSuccessful()) { body.close(); throw new ResponseException(response.code(), request.networkPolicy); } // Cache response is only null when the response comes fully from the network. Both completely // cached and conditionally cached responses will have a non-null cache response. Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK; // Sometimes response content length is zero when requests are being replayed. Haven't found // root cause to this but retrying the request seems safe to do so. if (loadedFrom == DISK && body.contentLength() == 0) { body.close(); throw new ContentLengthException("Received response with 0 content-length header."); } if (loadedFrom == NETWORK && body.contentLength() > 0) { stats.dispatchDownloadFinished(body.contentLength()); } return new Result(body.source(), loadedFrom);}
上面是2.5.2最新版本,该版本已经全面使用OkHttp下载图片,磁盘缓存也是由OkHttp提供。
至此,如何获取Bitmap分析完毕。
- Picasso源码完全解析(五)--图片的获取(BitmapHunter)
- Picasso源码分析(五):into方法追本溯源和责任链模式创建BitmapHunter
- Picasso源码完全解析(二)--Picasso实例的创建
- Picasso源码分析(六):BitmapHunter与请求结果的处理
- Picasso源码完全解析(一)--概述
- Picasso源码完全解析(四)--Action分发和执行
- Picasso源码完全解析(七)-- CleanupThread 取消请求
- Picasso源码完全解析(三)--Request和Action的创建
- Picasso源码完全解析(六)--请求的取消、暂停、和恢复
- Picasso源码的简单解析(一)
- Picasso源码的简单解析(二)
- Picasso源码的简单解析(一)
- 图片加载利器之Picasso(四)源码解析
- picasso图片框架源码解析
- Picasso源码解析--如何解决图片错位的问题
- Picasso框架源码解析(一)。
- Android 图片加载框架Picasso基本使用和源码完全解析
- AOP源码解析(五)获取代理
- JSON学习笔记(二)- 对象
- 文档生成字典
- Educational Codeforces Round 21E
- hdu 1013 Digital Roots
- openGL ES进阶教程(一)之粒子光束
- Picasso源码完全解析(五)--图片的获取(BitmapHunter)
- C++string类常用函数
- 指针和数组
- 细数WebView那些坑
- 2774 火烧赤壁(排序贪心)
- EPIC付款时供应商公司级别的冻结付款后付款消息为【找不到付款文件】调查
- Python遍历文件夹和读写文件的方法
- Markdown编辑器写博客
- vim--简单设置