publicvoidinto(ImageView target, Callback callback){ long started = System.nanoTime(); checkMain(); // 因为要显示在 ImageView 上,所以必须在主线程调用
if (target == null) { thrownew IllegalArgumentException("Target must not be null."); }
if (!data.hasImage()) { // 取图失败 picasso.cancelRequest(target); if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } return; }
if (deferred) { // 采用 fit 调整图片大小以适应 ImageView,延时操作 if (data.hasSize()) { // fit 后自然不能人工设置长宽 thrownew IllegalStateException("Fit cannot be used with resize."); } int width = target.getWidth(); int height = target.getHeight(); if (width == 0 || height == 0) { if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } picasso.defer(target, new DeferredRequestCreator(this, target, callback)); return; } data.resize(width, height); }
/** Skips memory cache lookup when processing a request. */ NO_CACHE(1 << 0), /** * Skips storing the final result into memory cache. Useful for one-off requests * to avoid evicting other bitmaps from the cache. */ NO_STORE(1 << 1);
/** Skips checking the disk cache and forces loading through the network. */ NO_CACHE(1 << 0),
/** * Skips storing the result into the disk cache. * <p> * <em>Note</em>: At this time this is only supported if you are using OkHttp. */ NO_STORE(1 << 1),
/** Forces the request through the disk cache only, skipping network. */ OFFLINE(1 << 2);
/** * A memory cache for storing the most recently used images. * <p> * <em>Note:</em> The {@link Cache} is accessed by multiple threads. You must ensure * your {@link Cache} implementation is thread safe when {@link Cache#get(String)} or {@link * Cache#set(String, android.graphics.Bitmap)} is called. */ publicinterfaceCache{ /** Retrieve an image for the specified {@code key} or {@code null}. */ Bitmap get(String key);
/** Store an image in the cache for the specified {@code key}. */ voidset(String key, Bitmap bitmap);
/** Returns the current size of the cache in bytes. */ intsize();
/** Returns the maximum size in bytes that the cache can hold. */ intmaxSize();
/** A memory cache which uses a least-recently used eviction policy. */ publicclassLruCacheimplementsCache{ final LinkedHashMap<String, Bitmap> map; // 有序 map privatefinalint maxSize;
/** Create a cache using an appropriate portion of the available RAM as the maximum size. */ publicLruCache(Context context){ this(Utils.calculateMemoryCacheSize(context)); // Utils.java 里用于计算内存的工具方法,返回的数值是1/7(约15%)应用可用内存。 }
/** Create a cache with a given maximum size in bytes. */ publicLruCache(int maxSize){ if (maxSize <= 0) { thrownew IllegalArgumentException("Max size must be positive."); } this.maxSize = maxSize; this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); // 第三个参数 true 表示 LinkedHashMap 的排序是按照最近 access,false则为最近 insertion }
publicabstractclassRequestHandler{ /** * Whether or not this {@link RequestHandler} can handle a request with the given {@link Request}. */ publicabstractbooleancanHandleRequest(Request data);
/** * Loads an image for the given {@link Request}. * * @param request the data from which the image should be resolved. * @param networkPolicy the {@link NetworkPolicy} for this request. */ publicabstract Result load(Request request, int networkPolicy)throws IOException; }
InputStream is = response.getInputStream(); // 拿到输入流,需要解析成 Bitmap if (is == null) { returnnull; } // 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 && response.getContentLength() == 0) { Utils.closeQuietly(is); thrownew ContentLengthException("Received response with 0 content-length header."); } if (loadedFrom == NETWORK && response.getContentLength() > 0) { stats.dispatchDownloadFinished(response.getContentLength()); } returnnew Result(is, loadedFrom); } }
可以看到它是将下载任务委托给了Downloader进行,Downloader的注释里描述的很清楚,它是“A mechanism to load images from external resources such as a disk cache and/or the internet.”,用于加载外部图片(相比于内存缓存而言)。最主要的是load方法
1
Response load(Uri uri, int networkPolicy)throws IOException;
其中Response的结构是
1 2 3 4 5 6
classResponse{ final InputStream stream; final Bitmap bitmap; finalboolean cached; // 图片是否来源自磁盘缓存(local disk cache) finallong contentLength; }
abstractclassAction<T> { staticclassRequestWeakReference<M> extendsWeakReference<M> { final Action action;
publicRequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q){ super(referent, q); this.action = action; } }
final Picasso picasso; final Request request; final WeakReference<T> target; finalboolean noFade; finalint memoryPolicy; finalint networkPolicy; finalint errorResId; final Drawable errorDrawable; final String key; final Object tag;
final DispatcherThread dispatcherThread; // 调度器线程 final Context context; final ExecutorService service; // 线程池 final Downloader downloader; // 下载器 final Map<String, BitmapHunter> hunterMap; // 线程 map final Map<Object, Action> failedActions; final Map<Object, Action> pausedActions; final Set<Object> pausedTags; final Handler handler; // DispatchHandler final Handler mainThreadHandler; // UI 变更 final Cache cache; final Stats stats; // 统计数据,包含命中缓存、未命中缓存、解码、下载计数 final List<BitmapHunter> batch; final NetworkBroadcastReceiver receiver; // 监听网络变化,调整并发线程数 finalboolean scansNetworkChanges;
classBitmapHunterimplementsRunnable{ finalint sequence; // 序列号,基于 AtomicInteger 实现 final Picasso picasso; // 单例 final Dispatcher dispatcher; // 任务调度器 final Cache cache; final Stats stats; final String key; final Request data; finalint memoryPolicy; int networkPolicy; final RequestHandler requestHandler;
Action action; List<Action> actions; // 一个 BitmapHunter 可以处理多个 Action Bitmap result; Future<?> future; Picasso.LoadedFrom loadedFrom; Exception exception; int exifRotation; // Determined during decoding of original resource. int retryCount; Priority priority; }
// If there was no Bitmap then we need to decode it from the stream. if (bitmap == null) { InputStream is = result.getStream(); // 解码图片 try { bitmap = decodeStream(is, data); } finally { Utils.closeQuietly(is); // quietly 的含义是无视所有异常 } } }