官方链接: http://square.github.io/picasso/
Git: https://github.com/square/picasso
本篇文章基于Picasso 2.71828,从基本的使用一步步分析
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
从get()方法来看,这个版本的Picasso和之前有所修改,之前用过的同学应该知道,之前是采用的with()方法
public static Picasso get() { if (singleton == null) { synchronized (Picasso.class) { if (singleton == null) { if (PicassoProvider.context == null) { throw new IllegalStateException("context == null"); } singleton = new Builder(PicassoProvider.context).build(); } } } return singleton; }
上面的代码用了一个Double Check的同步锁,singleton是volatile类型的,构造了一个Picasso对象,接着看PicassoProvider,这个类继承于ContentProvider,在onCreate方法中用getContext()获取了Context。然后看build方法
** Create the {@link Picasso} instance. */ public Picasso build() { Context context = this.context; if (downloader == null) { downloader = new OkHttp3Downloader(context); } if (cache == null) { cache = new LruCache(context); } if (service == null) { service = new PicassoExecutorService(); } if (transformer == null) { transformer = RequestTransformer.IDENTITY; } Stats stats = new Stats(cache); Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats); return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats, defaultBitmapConfig, indicatorsEnabled, loggingEnabled); } }
方法的注释写了,这个方法是创建Picasso的instance,这里面构造了
downloader :负责图片的实际加载
cache:内存缓存,LruCache,看过它源码的同学应该知道,他由LinkedHashMap实现,里面实际上是一个双向链表,每次修改会把最新的对象放到链表尾端,当链表达到最大长度,就会删除链表头的元素,这样就可以保留最近被使用的对象
service:Picasso的线程池
PicassoExecutorService() { super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory()); }DEFAULT_THREAD_COUNT=3,核心线程数和最大线程都是3个,提交的阻塞队列为具有优先级的无界队列队列,blockingQueue的实现原理就是Lock配合Full和Empty两个信号量,对队列进行操作的。
transformer:请求转换器
Stats:表示缓存的状态,Bitmap和download的状态
dispatcher:请求分发器,很重要,后面的文章分析。
load方法
public RequestCreator load(@Nullable String path) { if (path == null) { return new RequestCreator(this, null, 0); } if (path.trim().length() == 0) { throw new IllegalArgumentException("Path must not be empty."); } return load(Uri.parse(path)); }
load方法直接返回了一个RequestCreator,这个类是用来加载请求的,这里会创建一个Request builder对象,传入了图片的Uri,resourceId,以及BitmapConfig。返回了一个RequestCreator,方便链式调用。这个类还可以设置placeHolder,error等参数。
RequestCreator(Picasso picasso, Uri uri, int resourceId) { if (picasso.shutdown) { throw new IllegalStateException( "Picasso instance already shut down. Cannot submit new requests."); } this.picasso = picasso; this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig); }
into方法
public void into(ImageView target, Callback callback) { long started = System.nanoTime(); checkMain(); if (target == null) { throw new IllegalArgumentException("Target must not be null."); } if (!data.hasImage()) { picasso.cancelRequest(target); if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } return; } if (deferred) { if (data.hasSize()) { throw new 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); } Request request = createRequest(started); String requestKey = createKey(request); if (shouldReadFromMemoryCache(memoryPolicy)) { Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); if (bitmap != null) { picasso.cancelRequest(target); setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled); if (picasso.loggingEnabled) { log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY); } if (callback != null) { callback.onSuccess(); } return; } } if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } Action action = new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId, errorDrawable, requestKey, tag, callback, noFade); picasso.enqueueAndSubmit(action); }
首先会检测是否在主线程运行,通过getMainLooper的Thread去判断的。
static boolean isMain() { return Looper.getMainLooper().getThread() == Thread.currentThread(); }
接着判断图片信息和target是否为null,否则取消请求。
接着判断是否需要取缓存,取到了缓存就取消请求
if (shouldReadFromMemoryCache(memoryPolicy)) { Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); if (bitmap != null) { picasso.cancelRequest(target); setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled); if (picasso.loggingEnabled) { log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY); } if (callback != null) { callback.onSuccess(); } return; } }
这里两次提到了取消请求,我们看一下他是怎么做的
void cancelExistingRequest(Object target) { checkMain(); Action action = targetToAction.remove(target); if (action != null) { action.cancel(); dispatcher.dispatchCancel(action); } if (target instanceof ImageView) { ImageView targetImageView = (ImageView) target; DeferredRequestCreator deferredRequestCreator = targetToDeferredRequestCreator.remove(targetImageView); if (deferredRequestCreator != null) { deferredRequestCreator.cancel(); } } }
这里在检测主线程后,出现了一个Action类,Action可以看做单个图片加载的任务model,抽象类。是一个Request的包装类。
Action(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) { this.picasso = picasso; this.request = request; this.target = target == null ? null : new RequestWeakReference<>(this, target, picasso.referenceQueue); this.memoryPolicy = memoryPolicy; this.networkPolicy = networkPolicy; this.noFade = noFade; this.errorResId = errorResId; this.errorDrawable = errorDrawable; this.key = key; this.tag = (tag != null ? tag : this); }
targetToAction是一个Map,key为imageView,value为Action,取消请求时首先会移除这个值。然后在cancle dispatcher,这里面也是通过handler message来实现的,看到具体的实现
void performCancel(Action action) { String key = action.getKey(); BitmapHunter hunter = hunterMap.get(key); if (hunter != null) { hunter.detach(action); if (hunter.cancel()) { hunterMap.remove(key); if (action.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId()); } } } if (pausedTags.contains(action.getTag())) { pausedActions.remove(action.getTarget()); if (action.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId(), "because paused request got canceled"); } } Action remove = failedActions.remove(action.getTarget()); if (remove != null && remove.getPicasso().loggingEnabled) { log(OWNER_DISPATCHER, VERB_CANCELED, remove.getRequest().logId(), "from replaying"); } }
这里又出现了一个新类,BitmaoHunter,这是一个Runnable,用来开启线程下载,同时还可以解码图片,重点关注hunt方法,这里面会调用RequestHandler去下载图片,RequestHandler是一个抽象类,我们可以看NetworkRequestHandler中的load方法,这里会调用OkHttp去下载图片。
接着回去看CancelRequest的下半部分
if (target instanceof ImageView) { ImageView targetImageView = (ImageView) target; DeferredRequestCreator deferredRequestCreator = targetToDeferredRequestCreator.remove(targetImageView); if (deferredRequestCreator != null) { deferredRequestCreator.cancel(); } }
这里有一个DeferredRequestCreator类,这个类会对我们的target(ImageView)进行监听,它用来辅助获取我们ImageView的宽和高,然后就会重新执行请求创建。这里我们同样需要remove掉这里面的记录。
这篇就暂时先到这里,后面我们继续分析Dispatcher和into后面的部分。