Picasso源碼分析

0使用手冊

http://square.github.io/picasso/

1使用方法簡介

Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)

2 基本原理

這裏寫圖片描述

  1. 先使用Picasso.Builder生成一個單例Picasso,
  2. load的時候生成一個RequestCreator,再設置不同的Reqeust參數,into的時候生成一個Request,
  3. 再將Request和Target組合成Action,
  4. 由Picasso交給Dispatcher後臺執行,
  5. Dispatcher用Action生成BitmapHunter,交於PicassoExecutorService執行,BitmapHunter下載完成,執行相應的變換後,
  6. 用Handler通知Dispatcher緩存在內存中,
  7. Dispatcher再用Handler通知Picasso調用Action.complete()方法

3數據結構分析

RequestHandler: 根據Request獲取相應的內容。FileRequestHandler使用ContentResolver從文件中獲取。NetworkRequestHandler使用Downloader從網絡獲取。ResourceRequestHandler從apk資源中獲取。ContactsPhotoRequestHandler使用ContentResolver從通訊錄中獲取。ContentStreamRequestHandler使用ContentResolver獲取。

Downloader: 從網絡獲取時需要下載。UrlConnectionDownloader使用UrlConnection從網絡下載,HttpResponseCache可以讓UrlConnection使用文件緩存數據。OkHttpDownloader使用OkHttp庫來下載圖片,OkHttpClient.setCache可以讓OkHttp使用文件緩存

Stats:統計數據,緩存的命中率等等

Action:包含Request,Target和PlaceHolder,和異步加載後的回調,complete,error,cancel。

BitmapHunter: 異步Runnable任務。

4源代碼分析

  1. Picasso.Builder.build()
 /**
 2. 構造Picasso,使用Picasso.with會構造默認的方法,如果要自定義Picasso,則需要使用Builder,並在構造好了
 3. 之後使用Picasso.setSingletonInstance.
   */
/** Create the {@link Picasso} instance. */
    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);
    }
  1. RequestCreator.into()
 /**
     * 調用into方法時,使用Request.Builder創建一個Request,然後交給Dispatcher調度執行。
     * @param target
     */
  public void into(Target target) {
    long started = System.nanoTime();
    checkMain();

    if (target == null) {
      throw new IllegalArgumentException("Target must not be null.");
    }
    //當target是ImageView時,需要deferred,生成DeferredRequestCreator,利用ImageView的addOnPreDrawListener()當需要繪製的時候再來進行加載
    if (deferred) {
      throw new IllegalStateException("Fit cannot be used with a Target.");
    }

      //url爲空或者resourceid爲空,直接Cancel
    if (!data.hasImage()) {
      picasso.cancelRequest(target);
      target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
      return;
    }

    Request request = createRequest(started);
    String requestKey = createKey(request);

    if (shouldReadFromMemoryCache(memoryPolicy)) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        picasso.cancelRequest(target);
        target.onBitmapLoaded(bitmap, MEMORY);
        return;
      }
    }

    target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);

    Action action =
        new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
            requestKey, tag, errorResId);
    picasso.enqueueAndSubmit(action);
  }
  1. BitmapHunter.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;
      }
    }

      //使用RequestHandler加載圖片
    data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    if (result != null) {
      loadedFrom = result.getLoadedFrom();
      exifRotation = result.getExifOrientation();

      bitmap = result.getBitmap();

      //如果得到的不是圖片而是InputStream,則轉換成Bitmap
      if (bitmap == null) {
        InputStream is = result.getStream();
        try {
          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) {
        synchronized (DECODE_LOCK) {
          if (data.needsMatrixTransform() || exifRotation != 0) {
            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;
  }
  1. Dispatcher.performComplete()
//先判斷是否要寫內存緩存,然後將當前的hunter批量。
  //批量的原因是在Picasso的Handler當前可能還有沒有處理的。再Dispatcher這一級別再緩衝一下
  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");
    }
  }
  1. Picasso.comple()
//從Hunter中取出結果,調用Action.complete,or Action.error
  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);
    }

    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);
    }
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章