杨说:Picasso 2.8 使用和解析

1,288 阅读6分钟

目录

一、Picasso使用
二、Picasso初始化
三、Picasso配置
四、Picasso发送请求和缓存
五、Picasso对远程图片数据处理
六、总结

一 Picasso使用

 Picasso.get().load(uri).into(iv_image);

二 Picasso初始化

Picasso.get() 会初始化一个Picasso单例对象

2.1 双检测单例

Picasso.java

public static Picasso get() {
	//使用双检测机制保证
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
          //初始化从context 使用的是ContentProvider
          if (PicassoProvider.context == null) {
            throw new IllegalStateException("context == null");
          }
          //创建Picasso对象
          singleton = new Builder(PicassoProvider.context).build();
        }
      }
    }
    return singleton;
  }

2.2 ContentProvider初始化context

PicassoProvider.java

@RestrictTo(LIBRARY)
public final class PicassoProvider extends ContentProvider {

  @SuppressLint("StaticFieldLeak") static Context context;

  @Override public boolean onCreate() {
    context = getContext();
    return true;
  }
 ···
}

2.3 创建Picasso对象

singleton = new Builder(PicassoProvider.context).build(); 创建Builder对象

Picasso.Builder.java

 public Builder(@NonNull Context context) {
      if (context == null) {
        throw new IllegalArgumentException("Context must not be null.");
      }
      this.context = context.getApplicationContext();
    }

建造者模式创建Picasso对象

Picasso.Builder.java

public Picasso build() {
      Context context = this.context;

      if (downloader == null) {
      	//创建OkHttp3的下载器
        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);
	  //构造Picasso对象
      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }

Picasso对象初始化

Picasso.java

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; // Adjust this as internal handlers are added or removed.
    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);

    this.stats = stats;
    this.targetToAction = new WeakHashMap<>();
    this.targetToDeferredRequestCreator = new WeakHashMap<>();
    this.indicatorsEnabled = indicatorsEnabled;
    this.loggingEnabled = loggingEnabled;
    this.referenceQueue = new ReferenceQueue<>();
    this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
    this.cleanupThread.start();
  }

三 Picasso配置

Picasso.get().load(uri)会返回一个RequestCreator的对象,这个对象使用建造者模式配置请求参数,所有的load都是会返回RequestCreator,他是请求的配置中心,配置中心配置请求参数,比如占位图、缓存策略、转换。

Picasso.java

public RequestCreator load(@NonNull File file) {
    if (file == null) {
      //创建RequestCreator
      return new RequestCreator(this, null, 0);
    }
    return load(Uri.fromFile(file));
  }

四 Picasso发送请求和缓存

Picasso.get().load(uri).into(iv_image);开始请求图片数据,从缓存或者网络获取

4.1 发送请求

RequestCreator.java

public void into(ImageView target) {
    into(target, null);
  }
RequestCreator.java

public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    //检测是否在主线程调用、如果不是在主线程抛出异常
    checkMain();
	//目标不能为null
    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);
    //获取请求的key
    String requestKey = createKey(request);
	//如果从内存缓存中读取数据那直接从内存缓存中读取
    if (shouldReadFromMemoryCache(memoryPolicy)) {
     //从内存缓存中获取数据
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
      	//获取到数据取消请求
        picasso.cancelRequest(target);
        //设置bitmap
        setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
        ···
        //如果设置了回调调用回调
        if (callback != null) {
          callback.onSuccess();
        }
        return;
      }
    }
	//设置占位图
    if (setPlaceholder) {
      setPlaceholder(target, getPlaceholderDrawable());
    }
    //创建请求的Action
    Action action =
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);
	//添加并提交到队列
    picasso.enqueueAndSubmit(action);
  }

4.2 自适应测量控件大小并发送延迟请求

如果我们的target是ImageView并且设置了fit(),会先去测量view宽高,在获取宽高后延迟请求

RequestCreator.java

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

public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    ····

    //自适应大小,创建延迟请求
    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);
    }
   ····
  }

延迟请求创建new DeferredRequestCreator(this, target, callback),它实现了OnPreDrawListener,在view绘制的时候获取到view的宽度和高度,也实现了OnAttachStateChangeListener在view attach到View树上时注册OnPreDrawListener,detach时将OnPreDrawListener移除

DeferredRequestCreator.java

 DeferredRequestCreator(RequestCreator creator, ImageView target, Callback callback) {
    this.creator = creator;
    /弱引用引用target
    this.target = new WeakReference<>(target);
    this.callback = callback;
	//添加监听view attach状态
    target.addOnAttachStateChangeListener(this);

    // Only add the pre-draw listener if the view is already attached.
    // See: https://github.com/square/picasso/issues/1321
    //如果target已经添加到view上,直接调用attach回调
    if (target.getWindowToken() != null) {
      onViewAttachedToWindow(target);
    }
  }

view绘制完成回调OnPreDrawListener的onPreDraw()方法

DeferredRequestCreator.java

@Override public boolean onPreDraw() {
    //获取target
    ImageView target = this.target.get();
    if (target == null) {
      return true;
    }

    ViewTreeObserver vto = target.getViewTreeObserver();
    //如果View没有显示直接返回
    if (!vto.isAlive()) {
      return true;
    }
	//获取目标宽高
    int width = target.getWidth();
    int height = target.getHeight();
	//如果没有获取到返回
    if (width <= 0 || height <= 0) {
      return true;
    }
	//移除监听
    target.removeOnAttachStateChangeListener(this);
    vto.removeOnPreDrawListener(this);
    this.target.clear();
	//从新赋值宽高,然后调用into从新请求图片数据
    this.creator.unfit().resize(width, height).into(target, callback);
    return true;
  }

4.3 创建图片请求

Request request = createRequest(started);使用建造者模式创建请求

RequestCreator.java

public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    ···
    Request request = createRequest(started);
    ···
  }
RequestCreator.java

private Request createRequest(long started) {
	//请求id,使用的是tomicInteger保证线程安全
    int id = nextId.getAndIncrement();

    Request request = data.build();
    request.id = id;
    request.started = started;

    ···
    //可以在外部设置对请求进行转换
    Request transformed = picasso.transformRequest(request);
    if (transformed != request) {
      // If the request was changed, copy over the id and timestamp from the original.
      transformed.id = id;
      transformed.started = started;
      ···
    }

    return transformed;
  }

picasso.transformRequest(request);是对请求做转换或者是提供请求监听的切点


 Request transformRequest(Request request) {
   Request transformed = requestTransformer.transformRequest(request);
   ···
   return transformed;
 }

requestTransformer可以在创建Picasso的时候设置

Picasso.java

public Picasso build() {
      ···
      if (transformer == null) {
        transformer = RequestTransformer.IDENTITY;
      }

      ····
      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }

4.4 从内存中读取数据

shouldReadFromMemoryCache(memoryPolicy)如果读取策略配置了可从内存中读取数据,那开始从内存中读取数据,使用之前创建的key从LRUCache中读取picasso.quickMemoryCacheCheck(requestKey);


 public void into(ImageView target, Callback callback) {
    ···
    if (shouldReadFromMemoryCache(memoryPolicy)) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      //取消请求,设置图片,调用回调
      if (bitmap != null) {
        picasso.cancelRequest(target);
        setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
        ···
        if (callback != null) {
          callback.onSuccess();
        }
        return;
      }
    }
   ···
  }

从缓存中获取数据,如果命中,走命中分发流程,如果没有命中走未命中流程

Picasso.java

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

4.4.1 缓存命中和未命中

stats内部封装了HandlerThread,dispatchCacheHit(),dispatchCacheMiss()就是往子线程里发送数据

Stats.java

void dispatchCacheHit() {
    handler.sendEmptyMessage(CACHE_HIT);
  }
 
 void dispatchCacheMiss() {
    handler.sendEmptyMessage(CACHE_MISS);
  }

消息的处理

Stats.StatsHandler.java

@Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case CACHE_HIT:
          stats.performCacheHit();
          break;
        case CACHE_MISS:
          stats.performCacheMiss();
          break;
        ···
      }
    }

命中和未命中只是简单的执行了+1操作,用于oom快照使用

void performCacheHit() {
    cacheHits++;
  }

  void performCacheMiss() {
    cacheMisses++;
  }

4.5 从网络或者文件中获取图片

RequestCreator.java

public void into(ImageView target, Callback callback) {
    ···
	//设置占位图
    if (setPlaceholder) {
      setPlaceholder(target, getPlaceholderDrawable());
    }
	//创建请求的Action
    Action action =
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);
	//添加到请求队列
    picasso.enqueueAndSubmit(action);
  }
Picasso.java

void enqueueAndSubmit(Action action) {
    Object target = action.getTarget();
    if (target != null && targetToAction.get(target) != action) {
      // This will also check we are on the main thread.
      cancelExistingRequest(target);
      targetToAction.put(target, action);
    }
    submit(action);
  }
  
 void submit(Action action) {
    dispatcher.dispatchSubmit(action);
  }

dispatcher负责任务分发,是在创建Picasso的时候赋值的

Picasso.java

 public Picasso build() {
      ···

      Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }

dispatcher.dispatchSubmit(action);调用Handler向DispatcherThread发送消息,DispatcherThread是HandlerThread

Dispatcher.java

 void dispatchSubmit(Action action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
  }

消息的处理

Dispatcher.DispatcherHandler.java

@Override 
public void handleMessage(final Message msg) {
      switch (msg.what) {
        case REQUEST_SUBMIT: {
          Action action = (Action) msg.obj;
          dispatcher.performSubmit(action);
          break;
        }
        ····
      }
    }
Dispatcher.java

void performSubmit(Action action) {
    performSubmit(action, true);
  }

void performSubmit(Action action, boolean dismissFailed) {
    if (pausedTags.contains(action.getTag())) {
     //添加到暂停列表
      pausedActions.put(action.getTarget(), action);
      ···
      return;
    }
	//这里是真正封装请求调用的Runnable
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //关联request并设置优先级
      hunter.attach(action);
      return;
    }
	//如果线程池停止服务了返回
    if (service.isShutdown()) {
      ···
      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());
    }
   ···
  }

创建请求、 picasso.getRequestHandlers();存储了所有能处理图片请求的策略,requestHandler.canHandleRequest(request)检测是否能处理当前的图片请求,如果能处理返回,如果不能处理创建默认BitmapHunter

BitmapHunter.java

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

图片请求策略赋值是在创建Picasso的时候

Picasso.java

Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
      RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
      Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
    ···
    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));
    ····
  }

创建BitmapHunter后返回到Dispatcher中的performSubmit()方法然后将任务提交到线程池中hunter.future = service.submit(hunter);service是在创建Picasso对象时赋值的类型为PicassoExecutorService,默认线程数为3个,最大线程数也为3个,使用的是优先阻塞队列,创建线程工厂为后台线程,提交获取任务后会执行BitmapHunter的run方法

BitmapHunter.java

 @Override public void run() {
    try {
      //更新线程名称
      updateThreadName(data)
       ···
      //获取结果
      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);
    }
  }
BitmapHunter.java

Bitmap hunt() throws IOException {
    Bitmap bitmap = null;
    //内存中加载
    if (shouldReadFromMemoryCache(memoryPolicy)) {
      bitmap = cache.get(key);
      if (bitmap != null) {
        stats.dispatchCacheHit();
        loadedFrom = MEMORY;
        ···
        return bitmap;
      }
    }
    networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    //根据策略加载数据
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    ···

    return bitmap;
  }

4.5.1 从文件中获取图片

使用的是FileRequestHandler,调用okio处理图片数据


class FileRequestHandler extends ContentStreamRequestHandler {

   ···
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    Source source = Okio.source(getInputStream(request));
    return new Result(null, source, DISK, getFileExifRotation(request.uri));
  }

  static int getFileExifRotation(Uri uri) throws IOException {
    ExifInterface exifInterface = new ExifInterface(uri.getPath());
    return exifInterface.getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);
  }
}

4.5.2 从网络中获取图片

NetworkRequestHandler使用OKhttp3获取网络图片

NetworkRequestHandler.java

@Override public 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);
  }

五 Picasso对远程图片数据处理

无论是从网络函数从文件中获取图片数据,最后都是返回一个Result的对象,然后开始解码创建Bitmap

BitmapHunter.java

Bitmap hunt() throws IOException {
    ···
    //根据策略加载数据
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    if (result != null) {
      //获取bitmap
      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) {
      //分发解码
      stats.dispatchBitmapDecoded(bitmap);
      if (data.needsTransformation() || exifOrientation != 0) {
      	//加锁
        synchronized (DECODE_LOCK) {
          if (data.needsMatrixTransform() || exifOrientation != 0) {
            //如target宽高不为0,或者是需要旋转,那么开始进行变换
            bitmap = transformResult(data, bitmap, exifOrientation);
            ···
          }
          //定义了转换开始转换
          if (data.hasCustomTransformations()) {
            bitmap = applyCustomTransformations(data.transformations, bitmap);
            ···
            }
          }
        }
        if (bitmap != null) {
          //通知变换完成
          stats.dispatchBitmapTransformed(bitmap);
        }
      }
    }

    return bitmap;
  }

处理完图片转换回到BitmapHunter的run方法

BitmapHunter.java

 @Override public 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);
      }
  ···
  }
Dispatcher.java

 void dispatchComplete(BitmapHunter hunter) {
    handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
  }
Dispatcher.DispatcherHandler.java

@Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        ···
        case HUNTER_COMPLETE: {
          BitmapHunter hunter = (BitmapHunter) msg.obj;
          dispatcher.performComplete(hunter);
          break;
        }
        ···
      }
    }
Dispatcher.java

void performComplete(BitmapHunter hunter) {
    //设置到内存缓存
    if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
      cache.set(hunter.getKey(), hunter.getResult());
    }
    //清理工作
    hunterMap.remove(hunter.getKey());
    batch(hunter);
    ···
    }
  }
  
private void batch(BitmapHunter hunter) {
    if (hunter.isCancelled()) {
      return;
    }
    if (hunter.result != null) {
      //清空bitmap缓存
      hunter.result.prepareToDraw();
    }
    batch.add(hunter);
    /发送消息处理图片
    if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
      handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
    }
  }
Dispatcher.DispatcherHandler.java

@Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        ···
        case HUNTER_DELAY_NEXT_BATCH: {
          dispatcher.performBatchComplete();
          break;
        }
        ···
      }
    }
Dispatcher.java

void performBatchComplete() {
    List<BitmapHunter> copy = new ArrayList<>(batch);
    batch.clear();
//切换到主线程处理  mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
    //打点
    logBatch(copy);
  }

mainThreadHandler创建Dispatcher的时候传入的参数,是Picasso的一个成员变量

Picasso.java

 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;
          //noinspection ForLoopReplaceableByForEach
          //通知处理
          for (int i = 0, n = batch.size(); i < n; i++) {
            BitmapHunter hunter = batch.get(i);
            hunter.picasso.complete(hunter);
          }
          break;
        }
        ····
      }
    }
  };
Picasso.java

 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) {
      //noinspection ForLoopReplaceableByForEach
      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);
    }
  }
Picasso.java

private void deliverAction(Bitmap result, LoadedFrom from, Action action, Exception e) {
    if (action.isCancelled()) {
      return;
    }
    if (!action.willReplay()) {
      targetToAction.remove(action.getTarget());
    }
    if (result != null) {
      ···
      //通知回调
      action.complete(result, from);
      ···
    } else {
      action.error(e);
      ···
    }
  }

这个action就是在RequestCenter的int()方法创建的Action

RequestCenter.java

public void into(ImageView target, Callback callback) {
    ···
    Action action =
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);

    picasso.enqueueAndSubmit(action);
  }
ImageViewAction.java

@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;
    //想target设置图片
    PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);

    if (callback != null) {
      callback.onSuccess();
    }
  }
PicassoDrawable.java

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);
    target.setImageDrawable(drawable);
  }

六 总结

1 单例获取Picasso对象,调用load创建RequestCenter配置请求参数,并没有做Glide对控件生命周期的监控
2 调用into() 获取图片数据,它并没有Glide的两层内存缓存(当前活动的,和在内存中的),只有一种在内存中的缓存
3 磁盘的缓存也不像Glide的磁盘做细粒度的包含宽高的缓存,只是做了磁盘的普通缓存

杨说:Glide 4.11.0 生命周期监听
杨说:Glide 4.11.0 配置请求参数
杨说:Glide 4.11.0 发送请求准备工作
杨说:Glide 4.11.0 发送请求和缓存