Architecture(3)Picasso源碼分析

概述

前面分析了Volley的源碼,現(xiàn)在來(lái)看一下Picasso的源碼,其實(shí)Volley已經(jīng)具備了加載了網(wǎng)絡(luò)圖片的功能,只是性能不是很好,Picasso是Square公司推出的一款圖片加載框架,只能加載圖片,所以性能肯定會(huì)比Volley好,Picasso的很多設(shè)計(jì)實(shí)際上跟Volley很相似,后來(lái)看到Picasso中的一個(gè)類BitmapHunter的注釋,發(fā)現(xiàn)其實(shí)Picasso的作者也是參考了Volley的一些設(shè)計(jì)的。

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.
 

當(dāng)時(shí)看到注釋的最后一句就笑了,牛逼的框架也都是一步一步完善起來(lái)的,不過(guò)很佩服Picasso的作者,還在注釋中說(shuō)出來(lái),也是沒(méi)誰(shuí)了,下面總結(jié)一下Picasso的設(shè)計(jì)原理。

Picasso

Picasso大致的可以分這幾大塊,其實(shí)也比較好理解,如果我們只是加載一張圖片,那么很自然的可以連工具類都不用寫,用HttpUrlConnection或者用OkhttoUrlConnection去讀流,然后進(jìn)行轉(zhuǎn)碼,適當(dāng)?shù)谋壤s放就可以加載一張圖片,框架無(wú)非就是為了提高代碼的復(fù)用性以及加載速度,加載性能,不然也不會(huì)有人去寫去用,對(duì)于Bitmap,有一點(diǎn)需要注意的就是OOM,然后結(jié)合以上節(jié)點(diǎn),就是大部分框架需要考慮的東西。

正文

加載流程

先來(lái)看Picasso是如何調(diào)用的

Picasso.get()//獲取Picasso單例
  .load("url")//RequestCreator配置url,返回RequestCreator
  .placeholder(R.mipmap.ic_launcher)//RequestCreator配置占位圖,返回RequestCreator
  .error(R.mipmap.ic_launcher)//RequestCreator配置失敗的占位圖,返回RequestCreator
  .fit()//自動(dòng)縮放圖片,返回RequestCreator
  .into(new ImageView(this));//開(kāi)始加載圖片

這個(gè)是在Github上面的最新的demo里面,已經(jīng)用get代替了之前的with方法這里并沒(méi)有去畫流程圖或者類圖,感覺(jué)太大必要,因?yàn)樽约簩戇^(guò)簡(jiǎn)單的圖片加載框架,前面也分析過(guò)Volley的源碼,整體的流程都是大同小異的,對(duì)于Picasso而言,依然是先配置一些基本信息,緩存策略,占位圖等,然后就開(kāi)始根據(jù)緩存策略進(jìn)行數(shù)據(jù)讀取,所以,不再贅述,打算就Picasso的一些核心類進(jìn)行重點(diǎn)分析。

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

由于此方法是會(huì)在多線程中經(jīng)常被調(diào)用的,所以為了保證線程安全,采用了雙重檢查,其實(shí)我們也可以用靜態(tài)內(nèi)部類的形式來(lái)替代如下:

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();//檢測(cè)是否在主線程
  if (target == null) {
    throw new IllegalArgumentException("Target must not be null.");
  }
  if (!data.hasImage()) {
    //判斷是否傳入了圖片的加載地址
    picasso.cancelRequest(target);
    if (setPlaceholder) {
      //如果設(shè)置了占位圖,就進(jìn)行占位圖設(shè)置
      setPlaceholder(target, getPlaceholderDrawable());
    }
    return;
  }

  if (deferred) {
    //fit操作跟resize不能同時(shí)存在,這個(gè)也很好理解,
    //要么根據(jù)ImageView自己的尺寸要么根據(jù)我傳入的尺寸,魚(yú)跟熊掌不可兼得
    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的寬高有一個(gè)為0,也就是wrap的情況那么就必須延遲加載
      if (setPlaceholder) {
        //設(shè)置占位圖
        setPlaceholder(target, getPlaceholderDrawable());
      }
      // 在DeferredRequestCreator重新測(cè)量
      picasso.defer(target, new DeferredRequestCreator(this, target, callback));
      return;
    }
    //對(duì)重新設(shè)置ImageView的尺寸
    data.resize(width, height);
  }
  Request request = createRequest(started);//創(chuàng)建一個(gè)請(qǐng)求
  String requestKey = createKey(request);//創(chuàng)建緩存的key
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    //如果需要從緩存中讀取,則查找內(nèi)存緩存
    Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
    if (bitmap != null) {
      //獲取到緩存,取消掉請(qǐng)求
      picasso.cancelRequest(target);
      //設(shè)置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) {
        //成功的回調(diào)
        callback.onSuccess();
      }
      return;
    }
  }
  if (setPlaceholder) {
    //設(shè)置占位圖
    setPlaceholder(target, getPlaceholderDrawable());
  }
//創(chuàng)建ImageViewAction
  Action action = new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,errorDrawable, requestKey, tag, callback, noFade);
//Action入隊(duì)
  picasso.enqueueAndSubmit(action);
}

enqueueAndSubmit之后經(jīng)過(guò)一系列調(diào)用,最終調(diào)用了Diapatcher的performSubmit

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause過(guò),那么調(diào)用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通過(guò)Key獲取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //將action添加進(jìn)BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果線程池關(guān)閉,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //創(chuàng)建一個(gè)BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)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放進(jìn)了線程池,而B(niǎo)itmapHunter是個(gè)Runnable,那么所有的耗時(shí)操作肯定是放在run方法,追蹤之后執(zhí)行的是hunt方法,那么就來(lái)看一下hunt的具體流程

hunt

Bitmap hunt() throws IOException {
  Bitmap bitmap = null;
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    //再次讀取內(nèi)存緩存,因?yàn)椴煌恼?qǐng)求優(yōu)先級(jí)不一樣,很可能等到真正執(zhí)行的時(shí)候
    //當(dāng)前的url已經(jīng)被緩存了
    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;
  //如果沒(méi)有讀取緩存或者緩存讀取失敗,就開(kāi)始真正的請(qǐng)求
  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);
    //看看是否需要進(jìn)行變換前預(yù)處理,有的話就處理
    if (data.needsTransformation() || exifOrientation != 0) {
      synchronized (DECODE_LOCK) {
        //通過(guò)上鎖,每次只有一個(gè)進(jìn)行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;
}

接下來(lái)的就是將Bitmap回傳給ImageView了,還是在Dispatcher中,調(diào)用了performRequest方法

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

拿到數(shù)據(jù),在這里還是在工作線程里面,由于需要在主線程進(jìn)行顯示ImageView,所以需要切換線程,這里用到了 初始化的Handler,也就是通過(guò)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);
    }
}

主線程拿到傳遞過(guò)來(lái)的消息之后,經(jīng)過(guò)中轉(zhuǎn),最后還是到了ImageViewAction中,最終調(diào)用了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;
  //設(shè)置Bitmap
  PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
  if (callback != null) {
    callback.onSuccess();
  }
}

繼續(xù)看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);
  //最終設(shè)置的是一個(gè)BitmapDrawable
  target.setImageDrawable(drawable);
}

所以最終設(shè)置給ImageView的不是Bitmap,而是一個(gè)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);
    }
    //也是調(diào)用了setImageDrawable
    setImageDrawable(mRecycleableBitmapDrawable);
}

之所以設(shè)置的是BitmapDrawable,有兩個(gè)原因,一個(gè)是為了展示加載的動(dòng)畫,另一個(gè)是在debug模式下面可以繪制右上角的三角調(diào)試符號(hào),這些都是在初始化BitmapDrawable的時(shí)候加進(jìn)去的。

通過(guò)追蹤源碼的方式,可以了解到Picasso整體加載流程,有很多細(xì)節(jié)沒(méi)有分析到,不過(guò)我們已經(jīng)知道了,在分析過(guò)程中涉及到了很多類,其中有幾個(gè)類是反復(fù)出現(xiàn)的,Picasso,RequestCreator,Dispatcher,RequestHandler,Action,另外還有一些類,比如說(shuō)PicassoDrawable,LruCache,OkHttp3Downloader等,下面重點(diǎn)分析一下。

Picasso

成員變量

//清理線程,主要是用來(lái)清理ImageView被回收了的Request
private final CleanupThread cleanupThread;
//存放RequestHandler的集合
private final List<RequestHandler> requestHandlers;
//分發(fā)的一個(gè)關(guān)鍵類,主要用來(lái)轉(zhuǎn)發(fā)各種請(qǐng)求結(jié)果
final Dispatcher dispatcher;
//緩存
final Cache cache;
//存放不同Action的Map
final Map<Object, Action> targetToAction;
//存放延遲加載的RequestCreator,也就是fit狀態(tài)下獲取的寬或者為高的ImageView
final Map<ImageView, DeferredRequestCreator> targetToDeferredRequestCreator;
//引用隊(duì)列,每隔一段時(shí)間獲取被回收的target
final ReferenceQueue<Object> referenceQueue;

Picasso這個(gè)類持有了成員變量requestHandler集合,Action集合,Dispatcher,Cache這幾個(gè)前面提到的核心類,所以它自己實(shí)際上沒(méi)有什么特殊的功能,只是在間接的調(diào)用了這些核心類的功能,實(shí)際上是一個(gè)裝飾者模式,暴露給外部調(diào)用者調(diào)用,這也是為什么Picasso使用起來(lái)很簡(jiǎn)潔,原因就在于Picasso在這個(gè)類,封裝了所有的方法。

構(gòu)造方法

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;
    
    //構(gòu)造Builder對(duì)象
    public Builder(@NonNull Context context) {
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null.");
        }
        this.context = context.getApplicationContext();
    }
    //配置默認(rèn)信息
    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;
    }
    //配置內(nèi)存緩存策略
    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;
    }
    //配置回調(diào)接庫(kù)
    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;
    }

   //請(qǐng)求轉(zhuǎn)換器
    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;
    }
  //添加請(qǐng)求處理器
    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;
    }

   //指示器開(kāi)關(guān)
    public Builder indicatorsEnabled(boolean enabled) {
        this.indicatorsEnabled = enabled;
        return this;
    }

    //日志開(kāi)關(guān)
    public Builder loggingEnabled(boolean enabled) {
        this.loggingEnabled = enabled;
        return this;
    }
  //構(gòu)造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模式,所以跟大多數(shù)框架一樣,采用了建造者模式進(jìn)行構(gòu)造的。

cancelTag

通過(guò)tag取消請(qǐng)求

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,則進(jìn)行取消
    for (int i = 0, n = actions.size(); i < n; i++) {
        Action action = actions.get(i);
        if (tag.equals(action.getTag())) {
          //取消請(qǐng)求
            cancelExistingRequest(action.getTarget());
        }
    }
    List<DeferredRequestCreator> deferredRequestCreators =
            new ArrayList<>(targetToDeferredRequestCreator.values());
  //取消需要重新測(cè)量的deferredRequestCreator
    for (int i = 0, n = deferredRequestCreators.size(); i < n; i++) {
        DeferredRequestCreator deferredRequestCreator = deferredRequestCreators.get(i);
        if (tag.equals(deferredRequestCreator.getTag())) {
            deferredRequestCreator.cancel();
        }
    }
}

繼續(xù)看cancelExistingRequest

void cancelExistingRequest(Object target) {
    checkMain();
    Action action = targetToAction.remove(target);
    if (action != null) {
      //取消Action
        action.cancel();
      //取消BitmapHunter中的Action,一會(huì)兒再看Action中分析
        dispatcher.dispatchCancel(action);
    }
    if (target instanceof ImageView) {
        ImageView targetImageView = (ImageView) target;
        DeferredRequestCreator deferredRequestCreator =
                targetToDeferredRequestCreator.remove(targetImageView);
        if (deferredRequestCreator != null) {
          //取消延遲加載的請(qǐng)求
            deferredRequestCreator.cancel();
        }
    }
}

enqueueAndSubmit

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

resumeAction

void resumeAction(Action action) {
    Bitmap bitmap = null;
    //從內(nèi)存中進(jìn)行讀取
    if (shouldReadFromMemoryCache(action.memoryPolicy)) {
        bitmap = quickMemoryCacheCheck(action.getKey());
    }
    if (bitmap != null) {
        // 內(nèi)存讀取成功,完成整個(gè)流程
        deliverAction(bitmap, LoadedFrom.MEMORY, action, null);
    } else {
        // 重新加入隊(duì)列
        enqueueAndSubmit(action);
        if (loggingEnabled) {
            log(OWNER_MAIN, VERB_RESUMED, action.request.logId());
        }
    }
}

handler

//主線程中創(chuàng)建
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case HUNTER_BATCH_COMPLETE: {
              //請(qǐng)求完成
              @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;
            }
            //請(qǐng)求恢復(fù)
            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有很多重載方法,可以用來(lái)加載網(wǎng)絡(luò)url,讀取文件,讀取資源id,返回的是RequestCreator

pauseTag

暫停請(qǐng)求

 */
public void pauseTag(@NonNull Object tag) {
    if (tag == null) {
        throw new IllegalArgumentException("tag == null");
    }
   //diapatcher轉(zhuǎn)發(fā)
    dispatcher.dispatchPauseTag(tag);
}

resumeTag

public void resumeTag(@NonNull Object tag) {
    if (tag == null) {
        throw new IllegalArgumentException("tag == null");
    }
  //diapatcher轉(zhuǎn)發(fā)
    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) {
      //轉(zhuǎn)發(fā)請(qǐng)求
        deliverAction(result, from, single, exception);
    }
    if (hasMultiple) {
        //多個(gè)Action,依次遍歷轉(zhuǎn)發(fā)
        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();//清理引用隊(duì)列
    stats.shutdown();//關(guān)閉統(tǒng)計(jì)
    dispatcher.shutdown(); //關(guān)閉Dispatcher
    //取消所有延遲加載的請(qǐng)求
    for (DeferredRequestCreator deferredRequestCreator:targetToDeferredRequestCreator.values()) {
        deferredRequestCreator.cancel();
    }
    targetToDeferredRequestCreator.clear();
    shutdown = true;
}

RequestHandler

繼承關(guān)系

RequestHandler

RequestHandler有很多子類,這些是實(shí)際上進(jìn)行網(wǎng)絡(luò)請(qǐng)求的處理器,使用最多的是NetworkRequestHandler,其核心方法是load,主要交給子類實(shí)現(xiàn),看一下NetworkRequestHandler的實(shí)現(xiàn):

@Override
public Result load(Request request, int networkPolicy) throws IOException {
    //采用最新版的Okhttp3進(jìn)行網(wǎng)絡(luò)請(qǐng)求
    okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
    //獲取網(wǎng)絡(luò)返回的結(jié)果
    Response response = downloader.load(downloaderRequest);
    ResponseBody body = response.body();
    //省略若干代碼
   //判斷數(shù)據(jù)結(jié)果是來(lái)源于網(wǎng)絡(luò)還是磁盤
    Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;
    return new Result(body.source(), loadedFrom);
}

這里其實(shí)有一點(diǎn)需要注意的就是,我們?cè)赑icasso包下并沒(méi)有發(fā)現(xiàn)磁盤緩存,只有LruCache這個(gè)類,也就是通常所說(shuō)的內(nèi)存緩存,但是并沒(méi)有磁盤緩存,實(shí)際上Picasso的緩存全部交給了OKhttp來(lái)實(shí)現(xiàn)了,默認(rèn)的緩存路徑是由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();//請(qǐng)求ID
private final Picasso picasso;//Picasso引用
private final Request.Builder data;//builder構(gòu)造對(duì)象
private boolean noFade;//開(kāi)啟加載動(dòng)畫
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;//請(qǐng)求的tag

很簡(jiǎn)單,除了Picasso之外,沒(méi)有持有其它核心類的引用

構(gòu)造方法

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;
  //不管是傳入的什么參數(shù),Picasso最后都是通過(guò)Uri來(lái)進(jìn)行構(gòu)造的,這樣就需要針對(duì)不同的加載類型
  //來(lái)實(shí)現(xiàn)重載了
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}

Builder模式

參數(shù)Builder
//通過(guò)Uri構(gòu)造
public Builder(@NonNull Uri uri) {
    setUri(uri);
}
//通過(guò)資源ID構(gòu)造
public Builder(@DrawableRes int resourceId) {
    setResourceId(resourceId);
}
//同時(shí)傳入U(xiǎn)ri,資源ID,BitmapConfig
Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
    this.uri = uri;
    this.resourceId = resourceId;
    this.config = bitmapConfig;
}

Request構(gòu)造
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方法

自適應(yīng)ImageView的尺寸

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

重設(shè)尺寸

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是一個(gè)包裝類,會(huì)對(duì)我們的加載行為進(jìn)行一次包裝,包含了加載的信息以及回調(diào),先看一下它的繼承關(guān)系

繼承關(guān)系

Action

Action跟RequestHandler一樣,有很多子類,不過(guò)很常見(jiàn)的一個(gè)是ImageViewAction,一會(huì)兒會(huì)重點(diǎn)分析一下

成員變量

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的弱引用

構(gòu)造方法

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

下面看一下它的兩個(gè)方法,一個(gè)是complete一個(gè)是error方法,由于父類是抽象方法,所以只能交給子類去處理,所以下面以ImageViewAction來(lái)舉例說(shuō)明

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) {
      //成功回調(diào)
        callback.onSuccess();
    }
}

error

@Override
public void error(Exception e) {
    ImageView target = this.target.get();
    if (target == null) {
        return;
    }
    Drawable placeholder = target.getDrawable();
   //如果的動(dòng)畫還在繼續(xù),那么就停止動(dòng)畫
    if (placeholder instanceof AnimationDrawable) {
        ((AnimationDrawable) placeholder).stop();
    }
  //如果設(shè)置加載失敗的占位圖
    if (errorResId != 0) {
        target.setImageResource(errorResId);
    } else if (errorDrawable != null) {
     
        target.setImageDrawable(errorDrawable);
    }
    if (callback != null) {
      //失敗的回調(diào)
        callback.onError(e);
    }
}

實(shí)際上complete跟error的并沒(méi)有做什么,都只是做了簡(jiǎn)單的回調(diào),那么也就是說(shuō)Action只是一個(gè)包裝類,沒(méi)有額外的功能

BitmapHunter

Bitmap捕捉者,或者說(shuō)是Bitmap獵人,就是用來(lái)尋找Bitmap的一個(gè)類,繼承自Runnable,說(shuō)明可以用來(lái)進(jìn)行耗時(shí)操作。

注釋

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的全局鎖用以保證我們每次只能夠解碼一個(gè)Bitmap。因?yàn)榻獯a操作只是發(fā)生在后臺(tái)線程,所以為了避免解碼時(shí)太多的內(nèi)存占用導(dǎo)致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;

持有所有核心類

構(gòu)造方法

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

可以看到,很多參數(shù)都是傳遞過(guò)來(lái)的,也就是自己不持有。

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)) {
    //再次讀取內(nèi)存緩存,因?yàn)椴煌恼?qǐng)求優(yōu)先級(jí)不一樣,很可能等到真正執(zhí)行的時(shí)候
    //當(dāng)前的url已經(jīng)被緩存了
    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;
  //如果沒(méi)有讀取緩存或者緩存讀取失敗,就開(kāi)始真正的請(qǐng)求
  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);
    //看看是否需要進(jìn)行變換前預(yù)處理,有的話就處理
    if (data.needsTransformation() || exifOrientation != 0) {
      synchronized (DECODE_LOCK) {
        //通過(guò)上鎖,每次只有一個(gè)進(jìn)行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);
        }
    }
    如果沒(méi)有的話,重新創(chuàng)建一個(gè)
    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause過(guò),那么調(diào)用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通過(guò)Key獲取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //將action添加進(jìn)BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果線程池關(guān)閉,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //創(chuàng)建一個(gè)BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)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) {
    // 已經(jīng)paused過(guò),直接返回
    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;
        }
       //判斷當(dāng)前唯一的Action是否跟暫停的tag相同
        if (single != null && single.getTag().equals(tag)) {
          //從hunter中移除
            hunter.detach(single);
          //添加進(jìn)pausedActions
            pausedActions.put(single.getTarget(), single);
        }
        if (hasMultiple) {
          //如果有多個(gè)Action
            for (int i = joined.size() - 1; i >= 0; i--) {
                Action action = joined.get(i);
                if (!action.getTag().equals(tag)) {
                    continue;
                }
              //跟單個(gè)一樣
                hunter.detach(action);
                pausedActions.put(action.getTarget(), action);
            }
        }
    }
}

performResumeTag

void performResumeTag(Object tag) {
    // 移除恢復(fù)的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<>();
            }
          //添加進(jìn)List集合匯總
            batch.add(action);
          //從暫停的集合中移除
            i.remove();
        }
    }
    if (batch != null) {
      //切換到主線程,執(zhí)行resumeAction
       mainThreadHandler.sendMessage(
         mainThreadHandler.obtainMessage(REQUEST_BATCH_RESUME, batch));
    }
}

實(shí)際上performResumeTag在Picasso的分析中已經(jīng)說(shuō)明,如果沒(méi)有設(shè)置內(nèi)存緩存,那么相當(dāng)于重新開(kāi)啟一個(gè)請(qǐng)求,如果設(shè)置了內(nèi)存緩存,讀取失敗也會(huì)重新開(kāi)啟一個(gè)請(qǐng)求,只有在開(kāi)啟內(nèi)存緩存并且讀取成功performResumeTag才不會(huì)重新創(chuàng)建請(qǐng)求。

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);
            //計(jì)算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;
}

通過(guò)傳入目標(biāo)寬高以及實(shí)際的寬高進(jìn)行縮放,然后進(jìn)行縮放得到想要的尺寸

Dispatcher

成員變量

final DispatcherThread dispatcherThread;//HandlerThread,用于在子線程中創(chuàng)建Looper
final Context context;
final ExecutorService service;//線程池
final Downloader downloader;//圖片下載器
final Map<String, BitmapHunter> hunterMap;//存放BitmapHunter
final Map<Object, Action> failedActions;//失敗的請(qǐng)求
final Map<Object, Action> pausedActions;//暫停的請(qǐng)求
final Set<Object> pausedTags;//暫停的tag集合
final Handler handler;//Dispatcher中消息轉(zhuǎn)發(fā)的Handler
final Handler mainThreadHandler;//主線程中的Handler
final Cache cache;
final Stats stats;
final List<BitmapHunter> batch;//BitmapHunter集合
final NetworkBroadcastReceiver receiver;//網(wǎng)絡(luò)狀態(tài)監(jiān)聽(tīng)的廣播
final boolean scansNetworkChanges;網(wǎng)絡(luò)狀態(tài)是否切換的標(biāo)志

構(gòu)造方法

Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
           Downloader downloader, Cache cache, Stats stats) {
    this.dispatcherThread = new DispatcherThread();
    this.dispatcherThread.start();//啟動(dòng)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);
  //如果沒(méi)有獲取到網(wǎng)絡(luò)狀態(tài)改變的權(quán)限則全部為false
    this.scansNetworkChanges      =hasPermission(context,Manifest.permission.ACCESS_NETWORK_STATE);
  //創(chuàng)建網(wǎng)絡(luò)狀態(tài)監(jiān)聽(tīng)的廣播
    this.receiver = new NetworkBroadcastReceiver(this);
  //注冊(cè)廣播
    receiver.register();
}

Handler

這是區(qū)別于MainHandler的一個(gè)內(nèi)部的Handler,用在這里可以讓邏輯更加清晰,實(shí)際上不用也可以。

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: {//提交請(qǐng)求
                Action action = (Action) msg.obj;
                dispatcher.performSubmit(action);
                break;
            }
            case REQUEST_CANCEL: {//取消請(qǐng)求
                Action action = (Action) msg.obj;
                dispatcher.performCancel(action);
                break;
            }
            case TAG_PAUSE: {//暫停請(qǐng)求
                Object tag = msg.obj;
                dispatcher.performPauseTag(tag);
                break;
            }
            case TAG_RESUME: {//恢復(fù)請(qǐng)求
                Object tag = msg.obj;
                dispatcher.performResumeTag(tag);
                break;
            }
            case HUNTER_COMPLETE: {//請(qǐng)求完成
                BitmapHunter hunter = (BitmapHunter) msg.obj;
                dispatcher.performComplete(hunter);
                break;
            }
            case HUNTER_RETRY: {//請(qǐng)求重試
                BitmapHunter hunter = (BitmapHunter) msg.obj;
                dispatcher.performRetry(hunter);
                break;
            }
    }
}

NetworkBroadcastReceiver

網(wǎng)絡(luò)監(jiān)聽(tīng)的廣播

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);
          //將網(wǎng)絡(luò)狀態(tài)的變化通知內(nèi)部的Handler
       dispatcher.dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
        }
    }
}

dispatchNetworkStateChange最后還是調(diào)用了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);
  }
}

也就是根據(jù)不同的網(wǎng)絡(luò)狀態(tài)設(shè)置線程池的核心線程數(shù)以及最大線程數(shù)

performSubmit

void performSubmit(Action action, boolean dismissFailed) {
  //如果之前是pause過(guò),那么調(diào)用resume
    if (pausedTags.contains(action.getTag())) {
        pausedActions.put(action.getTarget(), action);
        return;
    }
   //通過(guò)Key獲取BitmapHunter
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      //將action添加進(jìn)BitmapHunter
        hunter.attach(action);
        return;
    }
    if (service.isShutdown()) {
      //如果線程池關(guān)閉,直接返回
        if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
   //創(chuàng)建一個(gè)BitmapHunter
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
   //拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)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中移除這個(gè)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() {
    // 關(guān)閉線程池
    if (service instanceof PicassoExecutorService) {
        service.shutdown();
    }
   //關(guān)閉下載器
    downloader.shutdown();
   //退出handler
    dispatcherThread.quit();
    //移除廣播
    Picasso.HANDLER.post(new Runnable() {
        @Override
        public void run() {
            receiver.unregister();
        }
    });
}

總結(jié)

上面分析了Picasso的核心類,還有一些比較重要的類,Lrucache,PicassoExecutorService,由于Lrucache跟Volley的DiskBaseCache并無(wú)區(qū)別,底層采用LinkedHashMap,通過(guò)使用的順序來(lái)進(jìn)行排序,容量不足時(shí)刪除最近最少使用的數(shù)據(jù),而PicassoExecutorService屬于線程池,之前也分析過(guò)。

Picasso相對(duì)于Volley注釋太少,不是很好閱讀,所幸命名比較規(guī)范,可以根據(jù)名字大致猜出這個(gè)類是干什么的,整體封裝性比Volley好,但是擴(kuò)展性不如Volley,不過(guò)都有很多值得學(xué)習(xí)的地方,下面簡(jiǎn)單對(duì)比分析一下:

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/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,917評(píng)論 25 709
  • Picasso,看的版本是v.2.5.2 使用方法,大概這么幾種加載資源的形式 還可以對(duì)圖片進(jìn)行一些操作:設(shè)置大小...
    Jinjins1129閱讀 410評(píng)論 0 3
  • 概述 在Android開(kāi)發(fā)界,大家都知到square出品必屬精品,圖片加載庫(kù)Picasso自然也是。本文就從源碼角...
    朔野閱讀 753評(píng)論 0 7
  • 此一刻,我在鄭州 秋風(fēng)卷起梧桐葉灑滿路面 而你在江南,蘇州的園林景觀 大概也抵不住這時(shí)令侵襲 你我都在這風(fēng)中搖曳 ...
    臨街的夏夜666閱讀 281評(píng)論 0 1
  • 寫在前面: 經(jīng)常有一些年輕的姑娘給我留言,向我了解結(jié)婚前,應(yīng)該清楚了解對(duì)方哪些事,才能下定決心在一起。 我仔細(xì)的思...
    妮妮小屋閱讀 5,080評(píng)論 23 113

友情鏈接更多精彩內(nèi)容