Architecture(3)Picasso源码分析

概述

前面分析了Volley的源码,现在来看一下Picasso的源码,其实Volley已经具备了加载了网络图片的功能,只是性能不是很好,Picasso是Square公司推出的一款图片加载框架,只能加载图片,所以性能肯定会比Volley好,Picasso的很多设计实际上跟Volley很相似,后来看到Picasso中的一个类BitmapHunter的注释,发现其实Picasso的作者也是参考了Volley的一些设计的。

Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since this will only ever happen in background threads we help avoid excessive memory thrashing as well as potential OOMs. Shamelessly stolen from Volley.
 

当时看到注释的最后一句就笑了,牛逼的框架也都是一步一步完善起来的,不过很佩服Picasso的作者,还在注释中说出来,也是没谁了,下面总结一下Picasso的设计原理。

Picasso

Picasso大致的可以分这几大块,其实也比较好理解,如果我们只是加载一张图片,那么很自然的可以连工具类都不用写,用HttpUrlConnection或者用OkhttoUrlConnection去读流,然后进行转码,适当的比例缩放就可以加载一张图片,框架无非就是为了提高代码的复用性以及加载速度,加载性能,不然也不会有人去写去用,对于Bitmap,有一点需要注意的就是OOM,然后结合以上节点,就是大部分框架需要考虑的东西。

正文

加载流程

先来看Picasso是如何调用的

Picasso.get()//获取Picasso单例
  .load("url")//RequestCreator配置url,返回RequestCreator
  .placeholder(R.mipmap.ic_launcher)//RequestCreator配置占位图,返回RequestCreator
  .error(R.mipmap.ic_launcher)//RequestCreator配置失败的占位图,返回RequestCreator
  .fit()//自动缩放图片,返回RequestCreator
  .into(new ImageView(this));//开始加载图片

这个是在Github上面的最新的demo里面,已经用get代替了之前的with方法这里并没有去画流程图或者类图,感觉太大必要,因为自己写过简单的图片加载框架,前面也分析过Volley的源码,整体的流程都是大同小异的,对于Picasso而言,依然是先配置一些基本信息,缓存策略,占位图等,然后就开始根据缓存策略进行数据读取,所以,不再赘述,打算就Picasso的一些核心类进行重点分析。

get方法

static volatile Picasso singleton = null;
public static Picasso get() {
    if (singleton == null) {
        synchronized (Picasso.class) {
            http:
            if (singleton == null) {
                if (PicassoProvider.context == null) {
                    throw new IllegalStateException("context == null");
                }
                singleton = new Builder(PicassoProvider.context).build();
            }
        }
    }
    return singleton;
}

由于此方法是会在多线程中经常被调用的,所以为了保证线程安全,采用了双重检查,其实我们也可以用静态内部类的形式来替代如下:

private static class NestedPicasso {
    public static Picasso singleton;
    static {
        System.out.println("instance = new SingletonTest()");
        if (PicassoProvider.context == null) {
            throw new IllegalStateException("context == null");
        }
        singleton = new Builder(PicassoProvider.context).build();
    }
}
public static Picasso get() {
    return NestedPicasso.singleton;
}

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) {
    //fit操作跟resize不能同时存在,这个也很好理解,
    //要么根据ImageView自己的尺寸要么根据我传入的尺寸,鱼跟熊掌不可兼得
    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 || target.isLayoutRequested()) {
      //如果ImageView的宽高有一个为0,也就是wrap的情况那么就必须延迟加载
      if (setPlaceholder) {
        //设置占位图
        setPlaceholder(target, getPlaceholderDrawable());
      }
      // 在DeferredRequestCreator重新测量
      picasso.defer(target, new DeferredRequestCreator(this, target, callback));
      return;
    }
    //对重新设置ImageView的尺寸
    data.resize(width, height);
  }
  Request request = createRequest(started);//创建一个请求
  String requestKey = createKey(request);//创建缓存的key
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    //如果需要从缓存中读取,则查找内存缓存
    Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
    if (bitmap != null) {
      //获取到缓存,取消掉请求
      picasso.cancelRequest(target);
      //设置Bitmap给ImageView
     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());
  }
//创建ImageViewAction
  Action action = new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,errorDrawable, requestKey, tag, callback, noFade);
//Action入队
  picasso.enqueueAndSubmit(action);
}

enqueueAndSubmit之后经过一系列调用,最终调用了Diapatcher的performSubmit

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause过,那么调用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通过Key获取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //将action添加进BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果线程池关闭,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //创建一个BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到线程池执行的结果,BitmapHunter肯定是个Runnable或者Future
    hunter.future = service.submit(hunter);
    //存入map中
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
        failedActions.remove(action.getTarget());
    }
    if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
}

我们知道把BitmapHunter放进了线程池,而BitmapHunter是个Runnable,那么所有的耗时操作肯定是放在run方法,追踪之后执行的是hunt方法,那么就来看一下hunt的具体流程

hunt

Bitmap hunt() throws IOException {
  Bitmap bitmap = null;
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    //再次读取内存缓存,因为不同的请求优先级不一样,很可能等到真正执行的时候
    //当前的url已经被缓存了
    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 {
          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) {
        //通过上锁,每次只有一个进行Decodeing
        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 (bitmap != null) {
        stats.dispatchBitmapTransformed(bitmap);
      }
    }
  }
  return bitmap;
}

接下来的就是将Bitmap回传给ImageView了,还是在Dispatcher中,调用了performRequest方法

void performComplete(BitmapHunter hunter) {
    if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
        cache.set(hunter.getKey(), hunter.getResult());
    }
    hunterMap.remove(hunter.getKey());
    batch(hunter);//追踪Bitmap
 
}

拿到数据,在这里还是在工作线程里面,由于需要在主线程进行显示ImageView,所以需要切换线程,这里用到了 初始化的Handler,也就是通过MainLooper初始化

batch

private void batch(BitmapHunter hunter) {
    if (hunter.isCancelled()) {
        return;
    }
    if (hunter.result != null) {
        hunter.result.prepareToDraw();
    }
    batch.add(hunter);
    if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
    //切换线程
      handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
    }
}

主线程拿到传递过来的消息之后,经过中转,最后还是到了ImageViewAction中,最终调用了complete方法

complete

@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
  if (result == null) {
    throw new AssertionError(
        String.format("Attempted to complete action with no result!\n%s", this));
  }
  ImageView target = this.target.get();
  if (target == null) {
    return;
  }
  Context context = picasso.context;
  boolean indicatorsEnabled = picasso.indicatorsEnabled;
  //设置Bitmap
  PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
  if (callback != null) {
    callback.onSuccess();
  }
}

继续看setBitmap

setBitmap

static void setBitmap(ImageView target, Context context, Bitmap bitmap,
    Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
  Drawable placeholder = target.getDrawable();
  if (placeholder instanceof Animatable) {
    ((Animatable) placeholder).stop();
  }
  PicassoDrawable drawable =
      new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
  //最终设置的是一个BitmapDrawable
  target.setImageDrawable(drawable);
}

所以最终设置给ImageView的不是Bitmap,而是一个BitmapDrawable,我们看一下setImagBitmap的源码

public void setImageBitmap(Bitmap bm) {
    // Hacky fix to force setImageDrawable to do a full setImageDrawable
    // instead of doing an object reference comparison
    mDrawable = null;
    if (mRecycleableBitmapDrawable == null) {
        mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
    } else {
        mRecycleableBitmapDrawable.setBitmap(bm);
    }
    //也是调用了setImageDrawable
    setImageDrawable(mRecycleableBitmapDrawable);
}

之所以设置的是BitmapDrawable,有两个原因,一个是为了展示加载的动画,另一个是在debug模式下面可以绘制右上角的三角调试符号,这些都是在初始化BitmapDrawable的时候加进去的。

通过追踪源码的方式,可以了解到Picasso整体加载流程,有很多细节没有分析到,不过我们已经知道了,在分析过程中涉及到了很多类,其中有几个类是反复出现的,Picasso,RequestCreator,Dispatcher,RequestHandler,Action,另外还有一些类,比如说PicassoDrawable,LruCache,OkHttp3Downloader等,下面重点分析一下。

Picasso

成员变量

//清理线程,主要是用来清理ImageView被回收了的Request
private final CleanupThread cleanupThread;
//存放RequestHandler的集合
private final List<RequestHandler> requestHandlers;
//分发的一个关键类,主要用来转发各种请求结果
final Dispatcher dispatcher;
//缓存
final Cache cache;
//存放不同Action的Map
final Map<Object, Action> targetToAction;
//存放延迟加载的RequestCreator,也就是fit状态下获取的宽或者为高的ImageView
final Map<ImageView, DeferredRequestCreator> targetToDeferredRequestCreator;
//引用队列,每隔一段时间获取被回收的target
final ReferenceQueue<Object> referenceQueue;

Picasso这个类持有了成员变量requestHandler集合,Action集合,Dispatcher,Cache这几个前面提到的核心类,所以它自己实际上没有什么特殊的功能,只是在间接的调用了这些核心类的功能,实际上是一个装饰者模式,暴露给外部调用者调用,这也是为什么Picasso使用起来很简洁,原因就在于Picasso在这个类,封装了所有的方法。

构造方法

Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
        RequestTransformer requestTransformer, 
        List<RequestHandler> extraRequestHandlers, 
        Stats stats,Bitmap.Config defaultBitmapConfig, 
        boolean indicatorsEnabled, 
        boolean loggingEnabled) {
    this.context = context;
    this.dispatcher = dispatcher;
    this.cache = cache;
    this.listener = listener;
    this.requestTransformer = requestTransformer;
    this.defaultBitmapConfig = defaultBitmapConfig;
    int builtInHandlers = 7; 
    int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
    List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
    allRequestHandlers.add(new ResourceRequestHandler(context));
    if (extraRequestHandlers != null) {
        allRequestHandlers.addAll(extraRequestHandlers);
    }
    //初始化所有的图片读取Handler
    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);
     this.targetToAction = new WeakHashMap<>();//软引用的Map
     this.targetToDeferredRequestCreator = new WeakHashMap<>();//软引用的Map
    
  
}

Builder

public static class Builder {
    private final Context context;
    private Downloader downloader;
    private ExecutorService service;
    private Cache cache;
    private Listener listener;
    private RequestTransformer transformer;
    private List<RequestHandler> requestHandlers;
    private Bitmap.Config defaultBitmapConfig;
    private boolean indicatorsEnabled;
    private boolean loggingEnabled;
    
    //构造Builder对象
    public Builder(@NonNull Context context) {
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null.");
        }
        this.context = context.getApplicationContext();
    }
    //配置默认信息
    public Builder defaultBitmapConfig(@NonNull Bitmap.Config bitmapConfig) {
        if (bitmapConfig == null) {
            throw new IllegalArgumentException("Bitmap config must not be null.");
        }
        this.defaultBitmapConfig = bitmapConfig;
        return this;
    }
    //配置下载器
    public Builder downloader(@NonNull Downloader downloader) {
        if (downloader == null) {
            throw new IllegalArgumentException("Downloader must not be null.");
        }
        if (this.downloader != null) {
            throw new IllegalStateException("Downloader already set.");
        }
        this.downloader = downloader;
        return this;
    }
     //配置线程池
    public Builder executor(@NonNull ExecutorService executorService) {
        if (executorService == null) {
            throw new IllegalArgumentException("Executor service must not be null.");
        }
        if (this.service != null) {
            throw new IllegalStateException("Executor service already set.");
        }
        this.service = executorService;
        return this;
    }
    //配置内存缓存策略
    public Builder memoryCache(@NonNull Cache memoryCache) {
        if (memoryCache == null) {
            throw new IllegalArgumentException("Memory cache must not be null.");
        }
        if (this.cache != null) {
            throw new IllegalStateException("Memory cache already set.");
        }
        this.cache = memoryCache;
        return this;
    }
    //配置回调接库
    public Builder listener(@NonNull Listener listener) {
        if (listener == null) {
            throw new IllegalArgumentException("Listener must not be null.");
        }
        if (this.listener != null) {
            throw new IllegalStateException("Listener already set.");
        }
        this.listener = listener;
        return this;
    }

   //请求转换器
    public Builder requestTransformer(@NonNull RequestTransformer transformer) {
        if (transformer == null) {
            throw new IllegalArgumentException("Transformer must not be null.");
        }
        if (this.transformer != null) {
            throw new IllegalStateException("Transformer already set.");
        }
        this.transformer = transformer;
        return this;
    }
  //添加请求处理器
    public Builder addRequestHandler(@NonNull RequestHandler requestHandler) {
        if (requestHandler == null) {
            throw new IllegalArgumentException("RequestHandler must not be null.");
        }
        if (requestHandlers == null) {
            requestHandlers = new ArrayList<>();
        }
        if (requestHandlers.contains(requestHandler)) {
            throw new IllegalStateException("RequestHandler already registered.");
        }
        requestHandlers.add(requestHandler);
        return this;
    }

   //指示器开关
    public Builder indicatorsEnabled(boolean enabled) {
        this.indicatorsEnabled = enabled;
        return this;
    }

    //日志开关
    public Builder loggingEnabled(boolean enabled) {
        this.loggingEnabled = enabled;
        return this;
    }
  //构造Picasso
    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的配置信息很多,所以采用的是Builder模式,所以跟大多数框架一样,采用了建造者模式进行构造的。

cancelTag

通过tag取消请求

public void cancelTag(@NonNull Object tag) {
    checkMain();
    if (tag == null) {
        throw new IllegalArgumentException("Cannot cancel requests with null tag.");
    }
    List<Action> actions = new ArrayList<>(targetToAction.values());
  //遍历所有的Action,如果找到该tag,则进行取消
    for (int i = 0, n = actions.size(); i < n; i++) {
        Action action = actions.get(i);
        if (tag.equals(action.getTag())) {
          //取消请求
            cancelExistingRequest(action.getTarget());
        }
    }
    List<DeferredRequestCreator> deferredRequestCreators =
            new ArrayList<>(targetToDeferredRequestCreator.values());
  //取消需要重新测量的deferredRequestCreator
    for (int i = 0, n = deferredRequestCreators.size(); i < n; i++) {
        DeferredRequestCreator deferredRequestCreator = deferredRequestCreators.get(i);
        if (tag.equals(deferredRequestCreator.getTag())) {
            deferredRequestCreator.cancel();
        }
    }
}

继续看cancelExistingRequest

void cancelExistingRequest(Object target) {
    checkMain();
    Action action = targetToAction.remove(target);
    if (action != null) {
      //取消Action
        action.cancel();
      //取消BitmapHunter中的Action,一会儿再看Action中分析
        dispatcher.dispatchCancel(action);
    }
    if (target instanceof ImageView) {
        ImageView targetImageView = (ImageView) target;
        DeferredRequestCreator deferredRequestCreator =
                targetToDeferredRequestCreator.remove(targetImageView);
        if (deferredRequestCreator != null) {
          //取消延迟加载的请求
            deferredRequestCreator.cancel();
        }
    }
}

enqueueAndSubmit

void enqueueAndSubmit(Action action) {
    Object target = action.getTarget();
    if (target != null && targetToAction.get(target) != action) {
        cancelExistingRequest(target);
        targetToAction.put(target, action);
    }
  //提交请求
    submit(action);
}

resumeAction

void resumeAction(Action action) {
    Bitmap bitmap = null;
    //从内存中进行读取
    if (shouldReadFromMemoryCache(action.memoryPolicy)) {
        bitmap = quickMemoryCacheCheck(action.getKey());
    }
    if (bitmap != null) {
        // 内存读取成功,完成整个流程
        deliverAction(bitmap, LoadedFrom.MEMORY, action, null);
    } else {
        // 重新加入队列
        enqueueAndSubmit(action);
        if (loggingEnabled) {
            log(OWNER_MAIN, VERB_RESUMED, action.request.logId());
        }
    }
}

handler

//主线程中创建
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case HUNTER_BATCH_COMPLETE: {
              //请求完成
              @SuppressWarnings("unchecked") 
              List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
                for (int i = 0, n = batch.size(); i < n; i++) {
                    BitmapHunter hunter = batch.get(i);
                    hunter.picasso.complete(hunter);
                }
                break;
            }
            //GC回收的ImageView
            case REQUEST_GCED: {
                Action action = (Action) msg.obj;
                action.picasso.cancelExistingRequest(action.getTarget());
                break;
            }
            //请求恢复
            case REQUEST_BATCH_RESUME:
                for (int i = 0, n = batch.size(); i < n; i++) {
                    Action action = batch.get(i);
                    action.picasso.resumeAction(action);
                }
                break;
            default:
                throw new AssertionError("Unknown handler message received: " + msg.what);
        }
    }
};

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));
}
//加载文件
public RequestCreator load(@NonNull File file) {
    if (file == null) {
        return new RequestCreator(this, null, 0);
    }
    return load(Uri.fromFile(file));
}

//加载资源id
public RequestCreator load(@DrawableRes int resourceId) {
    if (resourceId == 0) {
        throw new IllegalArgumentException("Resource ID must not be zero.");
    }
    return new RequestCreator(this, null, resourceId);
}

load有很多重载方法,可以用来加载网络url,读取文件,读取资源id,返回的是RequestCreator

pauseTag

暂停请求

 */
public void pauseTag(@NonNull Object tag) {
    if (tag == null) {
        throw new IllegalArgumentException("tag == null");
    }
   //diapatcher转发
    dispatcher.dispatchPauseTag(tag);
}

resumeTag

public void resumeTag(@NonNull Object tag) {
    if (tag == null) {
        throw new IllegalArgumentException("tag == null");
    }
  //diapatcher转发
    dispatcher.dispatchResumeTag(tag);
}

quickMemoryCacheCheck

Bitmap quickMemoryCacheCheck(String key) {
    Bitmap cached = cache.get(key);
    if (cached != null) {
        stats.dispatchCacheHit();
    } else {
        stats.dispatchCacheMiss();
    }
    return cached;
}

complete

void complete(BitmapHunter hunter) {
    Action single = hunter.getAction();
    List<Action> joined = hunter.getActions();
    boolean hasMultiple = joined != null && !joined.isEmpty();
    boolean shouldDeliver = single != null || hasMultiple;
    if (!shouldDeliver) {
        return;
    }
    Uri uri = hunter.getData().uri;
    Exception exception = hunter.getException();
    Bitmap result = hunter.getResult();
    LoadedFrom from = hunter.getLoadedFrom();
    if (single != null) {
      //转发请求
        deliverAction(result, from, single, exception);
    }
    if (hasMultiple) {
        //多个Action,依次遍历转发
        for (int i = 0, n = joined.size(); i < n; i++) {
            Action join = joined.get(i);
            deliverAction(result, from, join, exception);
        }
    }
    if (listener != null && exception != null) {
        listener.onImageLoadFailed(this, uri, exception);
    }
}

shutDown

public void shutdown() {
    if (this == singleton) {
        throw new UnsupportedOperationException("Default singleton instance cannot be shutdown.");
    }
    if (shutdown) {
        return;
    }
 
    cache.clear();  //清空缓存
    cleanupThread.shutdown();//清理引用队列
    stats.shutdown();//关闭统计
    dispatcher.shutdown(); //关闭Dispatcher
    //取消所有延迟加载的请求
    for (DeferredRequestCreator deferredRequestCreator:targetToDeferredRequestCreator.values()) {
        deferredRequestCreator.cancel();
    }
    targetToDeferredRequestCreator.clear();
    shutdown = true;
}

RequestHandler

继承关系

RequestHandler

RequestHandler有很多子类,这些是实际上进行网络请求的处理器,使用最多的是NetworkRequestHandler,其核心方法是load,主要交给子类实现,看一下NetworkRequestHandler的实现:

@Override
public Result load(Request request, int networkPolicy) throws IOException {
    //采用最新版的Okhttp3进行网络请求
    okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
    //获取网络返回的结果
    Response response = downloader.load(downloaderRequest);
    ResponseBody body = response.body();
    //省略若干代码
   //判断数据结果是来源于网络还是磁盘
    Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;
    return new Result(body.source(), loadedFrom);
}

这里其实有一点需要注意的就是,我们在Picasso包下并没有发现磁盘缓存,只有LruCache这个类,也就是通常所说的内存缓存,但是并没有磁盘缓存,实际上Picasso的缓存全部交给了OKhttp来实现了,默认的缓存路径是由Utils生成的,PICASSO_CACHE的值picasso-cache

static File createDefaultCacheDir(Context context) {
  File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE);
  if (!cache.exists()) {
    cache.mkdirs();
  }
  return cache;
}

成员变量

private static final AtomicInteger nextId = new AtomicInteger();//请求ID
private final Picasso picasso;//Picasso引用
private final Request.Builder data;//builder构造对象
private boolean noFade;//开启加载动画
private boolean deferred;//是否延迟加载
private boolean setPlaceholder = true;
private int placeholderResId;
private int errorResId;
private int memoryPolicy;
private int networkPolicy;
private Drawable placeholderDrawable;
private Drawable errorDrawable;
private Object tag;//请求的tag

很简单,除了Picasso之外,没有持有其它核心类的引用

构造方法

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;
  //不管是传入的什么参数,Picasso最后都是通过Uri来进行构造的,这样就需要针对不同的加载类型
  //来实现重载了
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}

Builder模式

参数Builder
//通过Uri构造
public Builder(@NonNull Uri uri) {
    setUri(uri);
}
//通过资源ID构造
public Builder(@DrawableRes int resourceId) {
    setResourceId(resourceId);
}
//同时传入Uri,资源ID,BitmapConfig
Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
    this.uri = uri;
    this.resourceId = resourceId;
    this.config = bitmapConfig;
}

Request构造
private Builder(Request request) {
    uri = request.uri;
    resourceId = request.resourceId;
    stableKey = request.stableKey;
    targetWidth = request.targetWidth;
    targetHeight = request.targetHeight;
    centerCrop = request.centerCrop;
    centerInside = request.centerInside;
    centerCropGravity = request.centerCropGravity;
    rotationDegrees = request.rotationDegrees;
    rotationPivotX = request.rotationPivotX;
    rotationPivotY = request.rotationPivotY;
    hasRotationPivot = request.hasRotationPivot;
    purgeable = request.purgeable;
    onlyScaleDown = request.onlyScaleDown;
    if (request.transformations != null) {
        transformations = new ArrayList<>(request.transformations);
    }
    config = request.config;
    priority = request.priority;
}
fit方法

自适应ImageView的尺寸

public RequestCreator fit() {
    deferred = true;
    return this;
}
resize

重设尺寸

public Builder resize(@Px int targetWidth, @Px int targetHeight) {
    if (targetWidth < 0) {
        throw new IllegalArgumentException("Width must be positive number or 0.");
    }
    if (targetHeight < 0) {
        throw new IllegalArgumentException("Height must be positive number or 0.");
    }
    if (targetHeight == 0 && targetWidth == 0) {
        throw new IllegalArgumentException("At least one dimension has to be positive number.");
    }
    this.targetWidth = targetWidth;
    this.targetHeight = targetHeight;
    return this;
}
属性配置
public Builder centerCrop(int alignGravity) {
    if (centerInside) {
        throw new IllegalStateException("Center crop can not be used after calling centerInside");
    }
    centerCrop = true;
    centerCropGravity = alignGravity;
    return this;
}

public Builder clearCenterCrop() {
    centerCrop = false;
    centerCropGravity = Gravity.CENTER;
    return this;
}

public Builder centerInside() {
    if (centerCrop) {
        throw new IllegalStateException("Center inside can not be used after calling centerCrop");
    }
    centerInside = true;
    return this;
}

Action

Action是一个包装类,会对我们的加载行为进行一次包装,包含了加载的信息以及回调,先看一下它的继承关系

继承关系

Action

Action跟RequestHandler一样,有很多子类,不过很常见的一个是ImageViewAction,一会儿会重点分析一下

成员变量

final Picasso picasso;
final Request request;
final WeakReference<T> target;
final boolean noFade;
final int memoryPolicy;
final int networkPolicy;
final int errorResId;
final Drawable errorDrawable;
final String key;
final Object tag;

包含了picasso,request以及target的弱引用

构造方法

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);
}

下面看一下它的两个方法,一个是complete一个是error方法,由于父类是抽象方法,所以只能交给子类去处理,所以下面以ImageViewAction来举例说明

complete

@Override
public void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (result == null) {
        throw new AssertionError(
                String.format("Attempted to complete action with no result!\n%s", this));
    }

    ImageView target = this.target.get();
    if (target == null) {
        return;
    }
    Context context = picasso.context;
    boolean indicatorsEnabled = picasso.indicatorsEnabled;
    PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
    if (callback != null) {
      //成功回调
        callback.onSuccess();
    }
}

error

@Override
public void error(Exception e) {
    ImageView target = this.target.get();
    if (target == null) {
        return;
    }
    Drawable placeholder = target.getDrawable();
   //如果的动画还在继续,那么就停止动画
    if (placeholder instanceof AnimationDrawable) {
        ((AnimationDrawable) placeholder).stop();
    }
  //如果设置加载失败的占位图
    if (errorResId != 0) {
        target.setImageResource(errorResId);
    } else if (errorDrawable != null) {
     
        target.setImageDrawable(errorDrawable);
    }
    if (callback != null) {
      //失败的回调
        callback.onError(e);
    }
}

实际上complete跟error的并没有做什么,都只是做了简单的回调,那么也就是说Action只是一个包装类,没有额外的功能

BitmapHunter

Bitmap捕捉者,或者说是Bitmap猎人,就是用来寻找Bitmap的一个类,继承自Runnable,说明可以用来进行耗时操作。

注释

Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since this will only ever happen in background threads we help avoid excessive memory thrashing as well as potential OOMs. Shamelessly stolen from Volley.

解码Bitmap的全局锁用以保证我们每次只能够解码一个Bitmap。因为解码操作只是发生在后台线程,所以为了避免解码时太多的内存占用导致OOM,借鉴于Volley。

成员变量

final Picasso picasso;
final Dispatcher dispatcher;
final Cache cache;
final Stats stats;
final String key;
final Request data;
final int memoryPolicy;
int networkPolicy;
final RequestHandler requestHandler;
Action action;
List<Action> actions;
Bitmap result;
Future<?> future;
Picasso.LoadedFrom loadedFrom;
Exception exception;
int exifOrientation; // Determined during decoding of original resource.
int retryCount;
Picasso.Priority priority;

持有所有核心类

构造方法

BitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action,RequestHandler requestHandler) {
    this.sequence = SEQUENCE_GENERATOR.incrementAndGet();
    this.picasso = picasso;
    this.dispatcher = dispatcher;
    this.cache = cache;
    this.stats = stats;
    this.action = action;
    this.key = action.getKey();
    this.data = action.getRequest();
    this.priority = action.getPriority();
    this.memoryPolicy = action.getMemoryPolicy();
    this.networkPolicy = action.getNetworkPolicy();
    this.requestHandler = requestHandler;
    this.retryCount = requestHandler.getRetryCount();
}

可以看到,很多参数都是传递过来的,也就是自己不持有。

run

@Override
public void run() {
    try {
        updateThreadName(data);
        //获取Bitmap
        result = hunt();
        if (result == null) {
            dispatcher.dispatchFailed(this);
        } else {
            dispatcher.dispatchComplete(this);
        }
    }
}

hunt

Bitmap hunt() throws IOException {
  Bitmap bitmap = null;
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    //再次读取内存缓存,因为不同的请求优先级不一样,很可能等到真正执行的时候
    //当前的url已经被缓存了
    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 {
          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) {
        //通过上锁,每次只有一个进行Decodeing
        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 (bitmap != null) {
        stats.dispatchBitmapTransformed(bitmap);
      }
    }
  }
  return bitmap;
}

forRequest

static BitmapHunter forRequest(
  Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action) {
    Request request = action.getRequest();
    List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
   //遍历已有的requestHandlers,看看能不能有能够处理的requestHandler
    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);
}

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause过,那么调用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通过Key获取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //将action添加进BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果线程池关闭,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //创建一个BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到线程池执行的结果,BitmapHunter肯定是个Runnable或者Future
    hunter.future = service.submit(hunter);
    //存入map中
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
        failedActions.remove(action.getTarget());
    }
    if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
}

performPauseTag

void performPauseTag(Object tag) {
    // 已经paused过,直接返回
    if (!pausedTags.add(tag)) {
        return;
    }
    // Go through all active hunters and detach/pause the requests
    // that have the paused tag.
    for (Iterator<BitmapHunter> it = hunterMap.values().iterator(); it.hasNext(); ) {
        BitmapHunter hunter = it.next();
        boolean loggingEnabled = hunter.getPicasso().loggingEnabled;
        Action single = hunter.getAction();
        List<Action> joined = hunter.getActions();
        boolean hasMultiple = joined != null && !joined.isEmpty();
        // Hunter has no requests, bail early.
        if (single == null && !hasMultiple) {
            continue;
        }
       //判断当前唯一的Action是否跟暂停的tag相同
        if (single != null && single.getTag().equals(tag)) {
          //从hunter中移除
            hunter.detach(single);
          //添加进pausedActions
            pausedActions.put(single.getTarget(), single);
        }
        if (hasMultiple) {
          //如果有多个Action
            for (int i = joined.size() - 1; i >= 0; i--) {
                Action action = joined.get(i);
                if (!action.getTag().equals(tag)) {
                    continue;
                }
              //跟单个一样
                hunter.detach(action);
                pausedActions.put(action.getTarget(), action);
            }
        }
    }
}

performResumeTag

void performResumeTag(Object tag) {
    // 移除恢复的tag
    if (!pausedTags.remove(tag)) {
        return;
    }
    List<Action> batch = null;
    for (Iterator<Action> i = pausedActions.values().iterator(); i.hasNext(); ) {
        Action action = i.next();
        if (action.getTag().equals(tag)) {
            if (batch == null) {
                batch = new ArrayList<>();
            }
          //添加进List集合汇总
            batch.add(action);
          //从暂停的集合中移除
            i.remove();
        }
    }
    if (batch != null) {
      //切换到主线程,执行resumeAction
       mainThreadHandler.sendMessage(
         mainThreadHandler.obtainMessage(REQUEST_BATCH_RESUME, batch));
    }
}

实际上performResumeTag在Picasso的分析中已经说明,如果没有设置内存缓存,那么相当于重新开启一个请求,如果设置了内存缓存,读取失败也会重新开启一个请求,只有在开启内存缓存并且读取成功performResumeTag才不会重新创建请求。

decodeStream

static Bitmap decodeStream(Source source, Request request) throws IOException {
    BufferedSource bufferedSource = Okio.buffer(source);
    boolean isWebPFile = Utils.isWebPFile(bufferedSource);
    boolean isPurgeable = request.purgeable && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
    BitmapFactory.Options options = RequestHandler.createBitmapOptions(request);
    boolean calculateSize = RequestHandler.requiresInSampleSize(options);
    if (isWebPFile || isPurgeable) {
        byte[] bytes = bufferedSource.readByteArray();
        if (calculateSize) {
            BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
            RequestHandler.calculateInSampleSize(
              request.targetWidth, request.targetHeight, options,request);
        }
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    } else {
        InputStream stream = bufferedSource.inputStream();
        if (calculateSize) {
            // TODO use an InputStream that buffers with Okio...
            MarkableInputStream markStream = new MarkableInputStream(stream);
            stream = markStream;
            markStream.allowMarksToExpire(false);
            long mark = markStream.savePosition(1024);
            BitmapFactory.decodeStream(stream, null, options);
            //计算Bitmap的尺寸
            RequestHandler.calculateInSampleSize(
              request.targetWidth, request.targetHeight, options,request);
            markStream.reset(mark);
            markStream.allowMarksToExpire(true);
        }
        Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
        if (bitmap == null) {
            throw new IOException("Failed to decode stream.");
        }
        return bitmap;
    }
}

calculateInSampleSize(RequestHandler的方法)

static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int height,
    BitmapFactory.Options options, Request request) {
  int sampleSize = 1;
  if (height > reqHeight || width > reqWidth) {
    final int heightRatio;
    final int widthRatio;
    if (reqHeight == 0) {
      sampleSize = (int) Math.floor((float) width / (float) reqWidth);
    } else if (reqWidth == 0) {
      sampleSize = (int) Math.floor((float) height / (float) reqHeight);
    } else {
      heightRatio = (int) Math.floor((float) height / (float) reqHeight);
      widthRatio = (int) Math.floor((float) width / (float) reqWidth);
      sampleSize = request.centerInside
          ? Math.max(heightRatio, widthRatio)
          : Math.min(heightRatio, widthRatio);
    }
  }
  options.inSampleSize = sampleSize;
  options.inJustDecodeBounds = false;
}

通过传入目标宽高以及实际的宽高进行缩放,然后进行缩放得到想要的尺寸

Dispatcher

成员变量

final DispatcherThread dispatcherThread;//HandlerThread,用于在子线程中创建Looper
final Context context;
final ExecutorService service;//线程池
final Downloader downloader;//图片下载器
final Map<String, BitmapHunter> hunterMap;//存放BitmapHunter
final Map<Object, Action> failedActions;//失败的请求
final Map<Object, Action> pausedActions;//暂停的请求
final Set<Object> pausedTags;//暂停的tag集合
final Handler handler;//Dispatcher中消息转发的Handler
final Handler mainThreadHandler;//主线程中的Handler
final Cache cache;
final Stats stats;
final List<BitmapHunter> batch;//BitmapHunter集合
final NetworkBroadcastReceiver receiver;//网络状态监听的广播
final boolean scansNetworkChanges;网络状态是否切换的标志

构造方法

Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
           Downloader downloader, Cache cache, Stats stats) {
    this.dispatcherThread = new DispatcherThread();
    this.dispatcherThread.start();//启动HandlerThread
    Utils.flushStackLocalLeaks(dispatcherThread.getLooper());
    this.context = context;
    this.service = service;
    this.hunterMap = new LinkedHashMap<>();
    this.failedActions = new WeakHashMap<>();//软引用
    this.pausedActions = new WeakHashMap<>();//软引用
    this.pausedTags = new HashSet<>();
    this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
    this.downloader = downloader;
    this.mainThreadHandler = mainThreadHandler;
    this.cache = cache;
    this.stats = stats;
    this.batch = new ArrayList<>(4);
    this.airplaneMode = Utils.isAirplaneModeOn(this.context);
  //如果没有获取到网络状态改变的权限则全部为false
    this.scansNetworkChanges      =hasPermission(context,Manifest.permission.ACCESS_NETWORK_STATE);
  //创建网络状态监听的广播
    this.receiver = new NetworkBroadcastReceiver(this);
  //注册广播
    receiver.register();
}

Handler

这是区别于MainHandler的一个内部的Handler,用在这里可以让逻辑更加清晰,实际上不用也可以。

private static class DispatcherHandler extends Handler {
    private final Dispatcher dispatcher;
   //传入子线程的Looper
    DispatcherHandler(Looper looper, Dispatcher dispatcher) {
        super(looper);
        this.dispatcher = dispatcher;
    }
    @Override
    public void handleMessage(final Message msg) {
        switch (msg.what) {
            case REQUEST_SUBMIT: {//提交请求
                Action action = (Action) msg.obj;
                dispatcher.performSubmit(action);
                break;
            }
            case REQUEST_CANCEL: {//取消请求
                Action action = (Action) msg.obj;
                dispatcher.performCancel(action);
                break;
            }
            case TAG_PAUSE: {//暂停请求
                Object tag = msg.obj;
                dispatcher.performPauseTag(tag);
                break;
            }
            case TAG_RESUME: {//恢复请求
                Object tag = msg.obj;
                dispatcher.performResumeTag(tag);
                break;
            }
            case HUNTER_COMPLETE: {//请求完成
                BitmapHunter hunter = (BitmapHunter) msg.obj;
                dispatcher.performComplete(hunter);
                break;
            }
            case HUNTER_RETRY: {//请求重试
                BitmapHunter hunter = (BitmapHunter) msg.obj;
                dispatcher.performRetry(hunter);
                break;
            }
    }
}

NetworkBroadcastReceiver

网络监听的广播

static class NetworkBroadcastReceiver extends BroadcastReceiver {
    static final String EXTRA_AIRPLANE_STATE = "state";
    private final Dispatcher dispatcher;
    NetworkBroadcastReceiver(Dispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }
    void register() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
        if (dispatcher.scansNetworkChanges) {
            filter.addAction(CONNECTIVITY_ACTION);
        }
        dispatcher.context.registerReceiver(this, filter);
    }
    void unregister() {
        dispatcher.context.unregisterReceiver(this);
    }
    @SuppressLint("MissingPermission")
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null) {
            return;
        }
        final String action = intent.getAction();
        if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
            if (!intent.hasExtra(EXTRA_AIRPLANE_STATE)) {
                return; /
            }
         dispatcher.dispatchAirplaneModeChange(
           intent.getBooleanExtra(EXTRA_AIRPLANE_STATE, false));
        } else if (CONNECTIVITY_ACTION.equals(action)) {
      ConnectivityManager connectivityManager = getService(context, CONNECTIVITY_SERVICE);
          //将网络状态的变化通知内部的Handler
       dispatcher.dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
        }
    }
}

dispatchNetworkStateChange最后还是调用了adjustThreadCount

void adjustThreadCount(NetworkInfo info) {
  if (info == null || !info.isConnectedOrConnecting()) {
    setThreadCount(DEFAULT_THREAD_COUNT);
    return;
  }
  switch (info.getType()) {
    case ConnectivityManager.TYPE_WIFI:
    case ConnectivityManager.TYPE_WIMAX:
    case ConnectivityManager.TYPE_ETHERNET:
      setThreadCount(4);
      break;
    case ConnectivityManager.TYPE_MOBILE:
      switch (info.getSubtype()) {
        case TelephonyManager.NETWORK_TYPE_LTE:  // 4G
        case TelephonyManager.NETWORK_TYPE_HSPAP:
        case TelephonyManager.NETWORK_TYPE_EHRPD:
          setThreadCount(3);
          break;
        case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
        case TelephonyManager.NETWORK_TYPE_CDMA:
        case TelephonyManager.NETWORK_TYPE_EVDO_0:
        case TelephonyManager.NETWORK_TYPE_EVDO_A:
        case TelephonyManager.NETWORK_TYPE_EVDO_B:
          setThreadCount(2);
          break;
        case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
        case TelephonyManager.NETWORK_TYPE_EDGE:
          setThreadCount(1);
          break;
        default:
          setThreadCount(DEFAULT_THREAD_COUNT);
      }
      break;
    default:
      setThreadCount(DEFAULT_THREAD_COUNT);
  }
}

也就是根据不同的网络状态设置线程池的核心线程数以及最大线程数

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause过,那么调用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通过Key获取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //将action添加进BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果线程池关闭,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //创建一个BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到线程池执行的结果,BitmapHunter肯定是个Runnable或者Future
    hunter.future = service.submit(hunter);
    //存入map中
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
        failedActions.remove(action.getTarget());
    }
    if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
}

performCancel

void performCancel(Action action) {
    String key = action.getKey();
    //获取hunter
    BitmapHunter hunter = hunterMap.get(key);
    if (hunter != null) {
      从hunter中移除这个Action
        hunter.detach(action);
        if (hunter.cancel()) {
            hunterMap.remove(key);
        }
    }
   //如果pausedTags中含有此Action,移除掉
    if (pausedTags.contains(action.getTag())) {
        pausedActions.remove(action.getTarget());
    }
   //尝试着从失败的Action中移除此Action
    Action remove = failedActions.remove(action.getTarget());
}

shutdown

void shutdown() {
    // 关闭线程池
    if (service instanceof PicassoExecutorService) {
        service.shutdown();
    }
   //关闭下载器
    downloader.shutdown();
   //退出handler
    dispatcherThread.quit();
    //移除广播
    Picasso.HANDLER.post(new Runnable() {
        @Override
        public void run() {
            receiver.unregister();
        }
    });
}

总结

上面分析了Picasso的核心类,还有一些比较重要的类,LrucachePicassoExecutorService,由于Lrucache跟Volley的DiskBaseCache并无区别,底层采用LinkedHashMap,通过使用的顺序来进行排序,容量不足时删除最近最少使用的数据,而PicassoExecutorService属于线程池,之前也分析过。

Picasso相对于Volley注释太少,不是很好阅读,所幸命名比较规范,可以根据名字大致猜出这个类是干什么的,整体封装性比Volley好,但是扩展性不如Volley,不过都有很多值得学习的地方,下面简单对比分析一下:

Volley Picasso
Request Request RequestCreator—>Request—>Action—>BitmapHunter
Cache DiskLruCache DiskLruCache&DiskDiskLruCache
RequstQueue BlockingQueue ThreadPoolExecutor
Dispatcher CacheDispatcher& NetworkDispatcher DispatcherThread
TaskAction cancel cancel,pause,resume

参考资料

http://blog.csdn.net/chdjj/article/details/49964901

https://blog.happyhls.me/category/android/picasso/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,799评论 25 707
  • Picasso,看的版本是v.2.5.2 使用方法,大概这么几种加载资源的形式 还可以对图片进行一些操作:设置大小...
    Jinjins1129阅读 344评论 0 3
  • 概述 在Android开发界,大家都知到square出品必属精品,图片加载库Picasso自然也是。本文就从源码角...
    朔野阅读 660评论 0 7
  • 此一刻,我在郑州 秋风卷起梧桐叶洒满路面 而你在江南,苏州的园林景观 大概也抵不住这时令侵袭 你我都在这风中摇曳 ...
    临街的夏夜666阅读 215评论 0 1
  • 写在前面: 经常有一些年轻的姑娘给我留言,向我了解结婚前,应该清楚了解对方哪些事,才能下定决心在一起。 我仔细的思...
    妮妮小屋阅读 4,999评论 23 113