Picasso 源码笔记

一、Picasso设置及使用:

在build.gradle中添加依赖:

compile 'com.squareup.picasso:picasso:2.5.2'

设置Picasso:

Picasso picasso = new Picasso.Builder(this)
        .memoryCache(new LruCache())       // 设置自定义的内存缓存
        .addRequestHandler(requestHandler) // 设置自定义的RequestHandler
        .defaultBitmapConfig(bitmapConfig) // 设置自定义的Bitmap Config
        .downloader(okHttpDownloader)      // 设置自定义的Downloader
        .executor(executorService)         // 设置自定义的线程池
        .requestTransformer(transformer)   // 设置自定义的Transformor
        .listener(listener)                // 添加Listener进行监听
        .loggingEnabled(true)              // 设置日志打印
        .build();
picasso.load(url)
        .placeholder(defaultDrawable)
        .error(errorDrawable)
        .resize(width, height)
        .centerInside()
        .into(imageView);

二、源码分析

(一)Picasso中重要类介绍

1. Action:描述Picasso的每次请求行为所包含的数据,以及每次请求完成和错误的处理,此类是所有Action的基类,继承时需要实现以下两个函数:

abstract void complete(Bitmap result, Picasso.LoadedFrom from);
abstract void error();
 主要成员变量:
  final Picasso picasso;
  final Request request;
  final WeakReference<T> target;    //外部传入的ImageView,
  final boolean noFade;                    //是否渐变的出现
  final int memoryPolicy;                  //内存策略
  final int networkPolicy;                  //网络策略
  final int errorResId;                        //错误时展示的图片id
  final Drawable errorDrawable;       //错误时展示的图片Drawable,和errorResId任给一个
  final String key;                          //根据每一个Request生成一个唯一的key值,用于在内存中缓存每一个key对应的bitmap,比如两个Request的uri及其他参数都一样,这时候就会直接读取缓存的值
  final Object tag;                           //用于暂停、重新运行或者取消某一个Request
  boolean willReplay;                      //标识是否需要重新请求
  boolean cancelled;                       //标识请求是否已取消
  
  我们注意到在Action的构造函数中有这么一个赋值
this.target = target == null ? null : new RequestWeakReference<T>(this, target, picasso.referenceQueue);
  
static class RequestWeakReference<M> extends WeakReference<M> {
    final Action action;
    public RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
      super(referent, q);
      this.action = action;
    }
}
    这里用到了弱引用,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

    弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
  
  下面介绍Action的子类:
  (1)FetchAction:获取图片,并在成功或者失败后回调onSuccess或者onError给调用者。一般用于提前缓存图片
  (2)GetAction:成功失败都没有回调,因为他是用在同步获取图片时使用,使用时不能放在主线程
  (3)TargetAction:将获取的图片放到target里面,使用时需要先实现Taget接口,这有助于自己对图片进行灵活的处理,比如保存等
public interface Target {
    void onBitmapLoaded(Bitmap bitmap, LoadedFrom from);
    void onBitmapFailed(Drawable errorDrawable);
    void onPrepareLoad(Drawable placeHolderDrawable);
}
  (4)NotificationAction:名字已经告诉我们这个图片是用于通知类消息中,在图片加载完成时会notify通知状态栏
  (5)AppWidgetAction:用于widget的图片加载,图片加载完成时会自动调用更新widget的方法
  (6)ImageViewAction:这个是最常用的Action,图片加载完成时会直接显示到ImageView

2. RequestHandler:请求处理的基类,对应不同请求都需要实现以下两个虚函数
public abstract boolean canHandleRequest(Request data); //判断是否能处理
public abstract Result load(Request request, int networkPolicy) throws IOException; //实际的网络请求或者图片资源加载

它里面还有一个对处理结果描述的静态内部类Result

public static final class Result {
    private final Picasso.LoadedFrom loadedFrom;  //MEMORY(Color.GREEN), DISK(Color.BLUE), NETWORK(Color.RED);
    private final Bitmap bitmap;
    private final InputStream stream;
    private final int exifOrientation;   //可交换图像文件的初始方向,比如0 90 180 270度
}
  RequestHandler的子类:
  (1)AssetRequestHandler:加载Asset中的图片资源,uri:file:///android_asset/xxx.png
  (2)ResourceRequestHandler:加载资源文件中的图片,uri:R.drawable.xxx.png
  (3)ContactsPhotoRequestHandler:联系人照片的图片加载,会先进行查询
  (4)MediaStoreRequestHandler:媒体资源库图片加载
  (5)ContentStreamRequestHandler:Provider图片  
  (6)FileRequestHandler:手机SD卡上面的图片加载
  (7)NetworkRequestHandler:网络请求加载图片,这是最重要的一种方式

  在Picasso的构造函数中会加入上面这个处理方法到数组中,调用的采用了责任链模式获取匹配的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);
    }
}
3. BitmapHunter implements Runnable:很明显,这是一个运行在某个线程中的获取图片的类,在他的run方法中会去下载图片并处理各种异常,包括异常重试。实际的获取工作是在RequestHandler类中获取的,对获取的bitmap进行数据解析和各种Transforms,包括用户自定义的

4. Picasso:这个类主要是利用建造者模式对Picasso相关参数进行设置,以及创建主线程的Handler对成功获取的图片进行ImageView的设置

5. Dispatcher:主要进行任务的分发,在这个类里面专门建立了一个HandlerThread线程来处理各种请求,比如把请求提交到线程池执行。

6. LruCache:采用最近最少使用是缓存的策略,正好利用了LinkedHashMap的特点

7. OkHttpDownloader:具体执行下载工作的类,load函数中设置了网络请求策略并采用OkHttp来获取图片

8. PicassoExecutorService:自定义线程池类,根据,可以在网络变化时动态调整核心线程池的数目,返回可以查询结果的FutureTask

9. RequestCreator:根据参数创建Picasso请求的类,主要是对图片的各种属性设置,比如大小,旋转,自定义变换等

10. UrlConnectionDownloader:对于没有okhttp的情况,采用原始的HttpURLConnection方式来下载图片

11. Stats:统计类,对下载图片的总大小、下载次数、变换次数等等进行统计,也是用了一个HandlerThread来专门负责


主要的类就介绍到这里,Picasso中的数据关联关系相对复杂,因此在进行下面的流程分析之前,先给一个数据关系结构图:


图一 Picasso数据结构图


(二)Picasso函数调用流程分析

    先从Picasso的初始化说起:我们可以使用Picasso默认的构造,这里使用了门面模式和单例模式方便我们使用

public static Picasso with(Context context) {
  if (singleton == null) {
    synchronized (Picasso.class) {
      if (singleton == null) {
        singleton = new Builder(context).build();
      }
    }
  }
  return singleton;
}
当然我们也可以自定义,这里使用了建造者模式来构建Picasso
  
Picasso picasso = new Picasso.Builder(this)  
        .memoryCache(new LruCache())         // 设置自定义的内存缓存  
        .addRequestHandler(requestHandler) // 设置自定义的RequestHandler  
        .defaultBitmapConfig(bitmapConfig)  // 设置自定义的Bitmap Config  
        .downloader(okHttpDownloader)       // 设置自定义的Downloader  
        .executor(executorService)                 // 设置自定义的线程池  
        .requestTransformer(transformer)      // 设置自定义的requestTransformer
        .listener(listener)                                // 添加Listener进行监听  
        .loggingEnabled(true)                        // 设置日志打印  
        .build(); 
        
我们来看看Picasso.build方法
public Picasso build() {
  Context context = this.context;

  if (downloader == null) {
    downloader = Utils.createDefaultDownloader(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);
}

这里我们需要来看下Utils.createDefaultDownloader

static Downloader createDefaultDownloader(Context context) {
  try {
    Class.forName("com.squareup.okhttp.OkHttpClient");
    return OkHttpLoaderCreator.create(context);
  } catch (ClassNotFoundException ignored) {
  }
  return new UrlConnectionDownloader(context);
}
这里会反射判断是否包含okhttp.OkHttpClient这个类,如果没有就会使用HttpURLConnection来下载。但是我们如果使用okhttp3的话肯定会返回HttpURLConnection,这时候如果想用okhttp3就需要自定义Downloader了。创建好了Picasso,我们来看下怎么使用的:

picasso.load(url)
  .memoryPolicy(MemoryPolicy.NO_CACHE)
  .networkPolicy(NetworkPolicy.NO_CACHE)
  .transform(new Transformation() //对获取的bitmap进行自定义变换
  .placeholder(defaultDrawable)
  .error(errorDrawable)
  .resize(width, height)
  .centerInside()
  .into(imageView); 

public RequestCreator load(Uri uri)
public RequestCreator load(String path)
public RequestCreator load(File file)
public RequestCreator load(int resourceId)

Picasso提供了4个load函数,分别加载不同的图片资源,第2,3两个函数都会转换调用第一个,注意到他们都返回了一个RequestCreator变量,load后面的函数都是RequestCreator提供的,它提供了对图片的各种设置,比如大小、旋转、自定义变换等,而实际开始处理图片的是into方法。

RequestCreator#into

public void into(ImageView target, Callback callback) {  
  long started = System.nanoTime();
  checkMain();  //检查是否主线程,不是则抛出异常

  if (target == null) {
    throw new IllegalArgumentException("Target must not be null.");
  }

  //判断是否设置了url或者resourceId,如果都没设置就取消请求并返回
  if (!data.hasImage()) {
    picasso.cancelRequest(target);  //取消并释放资源
    if (setPlaceholder) {
      setPlaceholder(target, getPlaceholderDrawable()); //设置前面传的错误占位图片
    }
    return;
  }

  //如果设置了.fit()方法deferred会置为true进入if判断
  if (deferred) {  
    if (data.hasSize()) { //如果有预先设置值会报错,因为fit方法会适应传入的ImageView的大小
      throw new IllegalStateException("Fit cannot be used with resize.");
    }
    int width = target.getWidth();
    int height = target.getHeight();
    if (width == 0 || height == 0) {  //为0说明ImageView还未渲染完成
      if (setPlaceholder) {
        setPlaceholder(target, getPlaceholderDrawable());
      }
      //这里DeferredRequestCreator implements ViewTreeObserver.OnPreDrawListener,当ImageView绘制之前会回调onPreDraw()函数,这个时候已经测量完了宽高的值,在onPreDraw()函数中会再次调用into函数,并把deferred置为false
      picasso.defer(target, new DeferredRequestCreator(this, target, callback));
      return;
    }
    data.resize(width, height);
  }

  //根据之前传入的图片uri, resourceId,大小,旋转角度等来build一个Request,并调用requestTransformer返回新的Request
  Request request = createRequest(started);
  //根据Request里面的参数来创建一个字符串的可以,用于对已经获取的bitmap进行缓存
  String requestKey = createKey(request);

  if (shouldReadFromMemoryCache(memoryPolicy)) {  //根据设置的策略来判断是否读取缓存
    Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);  //直接读取缓存中的bitmap
    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); //创建一个action并提交
}

这里引用一张流程图(https://blog.youkuaiyun.com/woliuyunyicai/article/details/51417839)


图二 into函数流程图

Picasso#enqueueAndSubmit->submit->dispatchSubmit

void enqueueAndSubmit(Action action) {
  Object target = action.getTarget();
  //更新存储的target对应的action,取消旧的
  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) {  //RequestCreator.java
  dispatcher.dispatchSubmit(action);  //利用dispatcher中的新线程专门处理分发任务
}

void dispatchSubmit(Action action) {  //Dispatcher.java
  handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));  //主线程向dispatcher线程发送任务
}

senMessage就从主线程切换到了dispatcher线程,下面来看下它处理了哪些message

Dispatcher#DispatcherHandler

private static class DispatcherHandler extends Handler {  //Dispatcher.java
  private final Dispatcher dispatcher;

  public 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: {  //根据tag来暂停
        Object tag = msg.obj;
        dispatcher.performPauseTag(tag);
        break;
      }
      case TAG_RESUME: {
        Object tag = msg.obj;
        dispatcher.performResumeTag(tag);
        break;
      }
      case HUNTER_COMPLETE: {  //bitmap获取完成
        BitmapHunter hunter = (BitmapHunter) msg.obj;
        dispatcher.performComplete(hunter);
        break;
      }
      case HUNTER_RETRY: {  //失败重试
        BitmapHunter hunter = (BitmapHunter) msg.obj;
        dispatcher.performRetry(hunter);
        break;
      }
      case HUNTER_DECODE_FAILED: {
        BitmapHunter hunter = (BitmapHunter) msg.obj;
        dispatcher.performError(hunter, false);
        break;
      }
      case HUNTER_DELAY_NEXT_BATCH: {  //批处理
        dispatcher.performBatchComplete();
        break;
      }
      case NETWORK_STATE_CHANGE: { //当网络状态变化时更新核心线程数。比如WIFI状态的核心线程就为4个,而4G,3G,2G状态下的线程数分别为3,2,1个;
        NetworkInfo info = (NetworkInfo) msg.obj;
        dispatcher.performNetworkStateChange(info);
        break;
      }
      case AIRPLANE_MODE_CHANGE: {
        dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
        break;
      }
      default:
        Picasso.HANDLER.post(new Runnable() {
          @Override public void run() {
            throw new AssertionError("Unknown handler message received: " + msg.what);
          }
        });
    }
  }
}

初始化函数中的looper是从HandlerThread中获取的,下面的handleMessage是运行在另外一个非主线程中的

REQUEST_SUBMIT把任务直接交给了dispatcher类来处理

Dispatcher#performSubmit

void performSubmit(Action action, boolean dismissFailed) {  //Dispatcher.java
  if (pausedTags.contains(action.getTag())) {  //如果tag已经标记为暂停,则直接返回了
    pausedActions.put(action.getTarget(), action);
    if (action.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
          "because tag '" + action.getTag() + "' is paused");
    }
    return;
  }

  //如果已经缓存过某个任务,则合并action。比如对同一个url的图片任务(图片的大小,旋转等参数也要一致),在两个不同的地方使用,第二次就会调用attach合并action。当bitmap请求回来之后会根据attach的action给不同的imageview赋值
  BitmapHunter hunter = hunterMap.get(action.getKey());
  if (hunter != null) {
    hunter.attach(action);
    return;
  }

  if (service.isShutdown()) {
    if (action.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
    }
    return;
  }

  //这里前面已经提到过,根据不同的加载任务,采用责任链模式来获取对应的RequestHandler,再构造一个BitmapHunter返回
  hunter = forRequest(action.getPicasso(), this, cache, stats, action);
  hunter.future = service.submit(hunter);  //提交到线程池处理
  hunterMap.put(action.getKey(), hunter);  //缓存key对应的任务
  if (dismissFailed) {
    failedActions.remove(action.getTarget());
  }

  if (action.getPicasso().loggingEnabled) {
    log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
  }
}
    submit提交到线程池后,线程池就会取出任务放在线程中执行,BitmapHunter是实现了runnable接口的,所以这时候就会跳转到BitmapHunter#run方法执行

BitmapHunter#run

@Override public void run() {
  try {
    updateThreadName(data);  //更新线程名字

    if (picasso.loggingEnabled) {
      log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
    }

    result = hunt();  //这里是重点,会实际去获取bitmap并根据大小,选择,变换等进行处理后返回

    //再次切换到dispatcher线程去执行
    if (result == null) {
      dispatcher.dispatchFailed(this);
    } else {
      dispatcher.dispatchComplete(this);
    }
  } catch (Downloader.ResponseException e) {
    if (!e.localCacheOnly || e.responseCode != 504) {
      exception = e;
    }
    dispatcher.dispatchFailed(this);
  } catch (NetworkRequestHandler.ContentLengthException e) {
    exception = e;
    dispatcher.dispatchRetry(this);  //出错重试,再次切换到dispatcher线程去重新发送请求
  } catch (IOException e) {
    exception = e;
    dispatcher.dispatchRetry(this);  //出错重试,再次切换到dispatcher线程去重新发送请求
  } 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);  //更改线程名称
  }
}

我们来看看重试的机制

Dispatcher#performRetry

void performRetry(BitmapHunter hunter) {
  if (hunter.isCancelled()) return;

  if (service.isShutdown()) { //服务已关闭
    performError(hunter, false); //移除缓存中当前的hunter,批处理其它的hunter
    return;
  }

  NetworkInfo networkInfo = null;
  if (scansNetworkChanges) {  // 用户是否允许联网
    ConnectivityManager connectivityManager = getService(context, CONNECTIVITY_SERVICE);
    networkInfo = connectivityManager.getActiveNetworkInfo();
  }

  boolean hasConnectivity = networkInfo != null && networkInfo.isConnected(); //判断是否联网
  //默认两次重试机会,如果重试次数大于0且已联网则返回true
  boolean shouldRetryHunter = hunter.shouldRetry(airplaneMode, networkInfo);
  boolean supportsReplay = hunter.supportsReplay();  //默认返回的true

  if (!shouldRetryHunter) {
    // Mark for replay only if we observe network info changes and support replay.
    boolean willReplay = scansNetworkChanges && supportsReplay;
    performError(hunter, willReplay);
    if (willReplay) {
      markForReplay(hunter);  //标记重试
    }
    return;
  }

  // If we don't scan for network changes (missing permission) or if we have connectivity, retry.
  if (!scansNetworkChanges || hasConnectivity) {
    if (hunter.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_RETRYING, getLogIdsForHunter(hunter));
    }
    //noinspection ThrowableResultOfMethodCallIgnored
    if (hunter.getException() instanceof NetworkRequestHandler.ContentLengthException) {
      hunter.networkPolicy |= NetworkPolicy.NO_CACHE.index;  //如果读取内容长度异常,则不再使用缓存
    }
    hunter.future = service.submit(hunter); //重新提交到线程池
    return;
  }

  performError(hunter, supportsReplay);

  if (supportsReplay) {
    markForReplay(hunter);
  }
}

再来看一下获取图片的实际请求类,在这里会调用okhttp执行网络请求

Dispatcher#hunt

Bitmap hunt() throws IOException {
  Bitmap bitmap = null;

  if (shouldReadFromMemoryCache(memoryPolicy)) { //如果缓存有则直接返回
    bitmap = cache.get(key);
    if (bitmap != null) {
      stats.dispatchCacheHit();
      loadedFrom = MEMORY;
      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
      }
      return bitmap;
    }
  }

  data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
  //这里会调用requestHandler中的load去获取图片,对应不同的资源,实际执行的load方法也不相同。例如对于网络请求会调用NetworkRequestHandler#load方法,这个方法会再去调用传入的OkHttpDownloader中的load方法,此方法会根据不同的网络策略,直接利用okhttp去请求数据
  RequestHandler.Result result = requestHandler.load(data, networkPolicy);
  if (result != null) {
    loadedFrom = result.getLoadedFrom();
    exifRotation = result.getExifOrientation();

    bitmap = result.getBitmap();

    // If there was no Bitmap then we need to decode it from the stream.
    if (bitmap == null) {
      InputStream is = result.getStream();
      try {
        //根据用户设定的宽和高来计算options.inSampleSize,再根据这个把数据流解析成bitmap
        bitmap = decodeStream(is, data);
      } finally {
        Utils.closeQuietly(is);
      }
    }
  }

  if (bitmap != null) {
    if (picasso.loggingEnabled) {
      log(OWNER_HUNTER, VERB_DECODED, data.logId());
    }
    stats.dispatchBitmapDecoded(bitmap); //更新统计
    if (data.needsTransformation() || exifRotation != 0) {
      //锁定一个空对象,保证同一个时间自由一个线程在处理各种变换,以避免OOM,作者说是从Volley学过来的
      synchronized (DECODE_LOCK) { 
        if (data.needsMatrixTransform() || exifRotation != 0) {
          //进行大小,旋转,centerCrop,centerCrop等操作
          bitmap = transformResult(data, bitmap, exifRotation);
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
          }
        }
        //如果用户设置了自定义的变换,则回调用户已经设置好的变换方法
        if (data.hasCustomTransformations()) {
          bitmap = applyCustomTransformations(data.transformations, bitmap);
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
          }
        }
      }
      if (bitmap != null) {
        stats.dispatchBitmapTransformed(bitmap);
      }
    }
  }

  return bitmap;
}
   到这里,经过网络请求,各种变换后的bitmap总算得到了,但是现在在线程池分配的线程里,我们马上调用Dispatcher的方法切换到dispatcher线程进行后续的bitmap处理

Dispatcher#performComplete->batch->performBatchComplete

void performComplete(BitmapHunter hunter) {
  if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
    cache.set(hunter.getKey(), hunter.getResult());判断是否写入缓存
  }
  hunterMap.remove(hunter.getKey());
  batch(hunter);  //加入批处理列表
  if (hunter.getPicasso().loggingEnabled) {
    log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
  }
}

private void batch(BitmapHunter hunter) {
  if (hunter.isCancelled()) {
    return;
  }
  batch.add(hunter); //加入批处理列表
  if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {  //判断是否已经发送了此消息,避免重复发送
    handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);  //delay200ms,在此期间的都会合并处理
  }
}

void performBatchComplete() {
  List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch);  //深拷贝一份
  batch.clear();
  //发送给Picasso中的Handler处理,因为需要在主线程更新UI
  mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
  logBatch(copy);
}

最后把要处理的列表传给了主线程的Handler,那么我们继续跟进

Picasso#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;
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, n = batch.size(); i < n; i++) {
          BitmapHunter hunter = batch.get(i);
          hunter.picasso.complete(hunter); //循环处理所有的hunter
        }
        break;
      }
      case REQUEST_GCED: {
        Action action = (Action) msg.obj;
        if (action.getPicasso().loggingEnabled) {
          log(OWNER_MAIN, VERB_CANCELED, action.request.logId(), "target got garbage collected");
        }
        action.picasso.cancelExistingRequest(action.getTarget());
        break;
      }
      case REQUEST_BATCH_RESUME:
        @SuppressWarnings("unchecked") List<Action> batch = (List<Action>) msg.obj;
        //noinspection ForLoopReplaceableByForEach
        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);
    }
  }
};

注意到这里的Looper传入的是MainLooper,也就是说handleMessage是在主线程运行的,所以可以更新UI。如果new Handler()时不传入Looper,那么会使用创建时线程的Looper,换句话说那就是在哪个线程创建就运行在哪个线程。

Picasso#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();    //获取在BitmapHunter中获取的bitmap
  LoadedFrom from = hunter.getLoadedFrom();

  if (single != null) {
    deliverAction(result, from, single);  //处理当前的actin
  }

  //如果之前调用过Attach方法,这时候还会有其他的action
  if (hasMultiple) {
    //noinspection ForLoopReplaceableByForEach
    for (int i = 0, n = joined.size(); i < n; i++) {
      Action join = joined.get(i);
      deliverAction(result, from, join);
    }
  }

  if (listener != null && exception != null) {
    listener.onImageLoadFailed(this, uri, exception); //异常回调
  }
}
Picasso#deliverAction
private void deliverAction(Bitmap result, LoadedFrom from, Action action) {
  if (action.isCancelled()) {
    return;
  }
  if (!action.willReplay()) {
    targetToAction.remove(action.getTarget());
  }
  if (result != null) {
    if (from == null) {
      throw new AssertionError("LoadedFrom cannot be null.");
    }
    action.complete(result, from);  //调用action的complete方法处理bitmap,具体怎么处理要看action的实现类
    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
    }
  } else {
    action.error();
    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_ERRORED, action.request.logId());
    }
  }
}
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); //接着又调了静态函数setBitmap

  if (callback != null) {
    callback.onSuccess(); //如果设置了回调函数则回调
  }
}
PicassoDrawable#setBitmap
static void setBitmap(ImageView target, Context context, Bitmap bitmap,
    Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
  Drawable placeholder = target.getDrawable();
  if (placeholder instanceof AnimationDrawable) {
    ((AnimationDrawable) placeholder).stop();
  }
  PicassoDrawable drawable =
      new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
  target.setImageDrawable(drawable);  //这里用到了我们常用的方法
}

引用一张图来描述请求流程: 

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值