picasso的源碼分析(一)

picasso的使用很是簡單。咱們只須要一行代碼就夠java

picasso.with(context).load(uri).into(imageView);算法

先看with方法緩存

public static Picasso with(Context context) {
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
          singleton = new Builder(context).build();
        }
      }
    }
    return singleton;
  }

這裏使用了單例模式,並且是雙重檢測鎖的方法。 另外還使用到了Builder模式,由於Picasso對象的建立很是複雜ide

咱們直接看build方法post

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

    這裏先初始化Downloader,Cache(這裏使用的LRU算法),PicassoExecutorService(這是Picasso本身實現的線程池),Transformer(當請求被submit時能夠調用他去修改請求)。ui

    接下來是Stats stats = new Stats(cache).this

    能夠看下這裏類裏面的主要的成員變量url

    

final HandlerThread statsThread;
  final Cache cache;
  final Handler handler;
  long cacheHits;
  long cacheMisses;
  long totalDownloadSize;
  long totalOriginalBitmapSize;
  long totalTransformedBitmapSize;
  long averageDownloadSize;
  long averageOriginalBitmapSize;
  long averageTransformedBitmapSize;
  int downloadCount;
  int originalBitmapCount;
  int transformedBitmapCount;

    主要爲了記錄一些緩存的命中次數,下載的文件大小,下載次數,原始文件大小等等信息,暫時先不看是幹什麼用的spa

    這裏有一個Handler,是作什麼用的呢?好比Picasso請求一個以前已經請求過,如今已經被緩存過的圖片,這時候在訪問它就是命中了,這時候能夠調用 stats.dispatchCacheHit();線程

 void dispatchCacheHit() {

    handler.sendEmptyMessage(CACHE_HIT);

  }
@Override public void handleMessage(final Message msg) {

      switch (msg.what) {

        case CACHE_HIT:

          stats.performCacheHit();

          break;

        case CACHE_MISS:

          stats.performCacheMiss();

          break;

        case BITMAP_DECODE_FINISHED:

          stats.performBitmapDecoded(msg.arg1);

          break;

        case BITMAP_TRANSFORMED_FINISHED:

          stats.performBitmapTransformed(msg.arg1);

          break;

        case DOWNLOAD_FINISHED:

          stats.performDownloadFinished((Long) msg.obj);

          break;

        default:

          Picasso.HANDLER.post(new Runnable() {

            @Override public void run() {

              throw new AssertionError("Unhandled stats message." + msg.what);

            }

          });

      }

    }

就執行了performCacheHit方法,即cacheHits++

這裏爲何繞了一個大彎子,picasso先是調用stats.dispatchCacheHit().該方法裏經過handler發送一個消息,而後接收到消息後,把cacheHits++。爲何不直接在dispatchCacheHit方法裏cacheHits++。好比像downloadCount,totalDownloadSize等成員變量就是直接++的。

build()裏還有一行Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

Dispatcher是幹什麼的呢?這是一個分發器,全部的請求都在這裏分發。

最後new Picasso對象返回。

--------------------------------with()到底結束--------------------

public RequestCreator load(Uri uri) {

    return new RequestCreator(this, uri, 0);

  }

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.");
    }
    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);
    String requestKey = createKey(request);
    if (shouldReadFromMemoryCache(memoryPolicy)) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      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);
  }

    首先記錄下開始時間,而後檢查是否是主線程執行的。

    if (!data.hasImage())是什麼意思呢?data是this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);

boolean hasImage() {

      return uri != null || resourceId != 0;

    }

因此這裏是返回true的,因此暫時判斷裏的內容沒有執行

if (deferred) {//deferred在這裏是默認值false,因此花括號裏的內容也沒有執行

  Request request = createRequest(started);    //這裏建立了請求,給請求惟一的id,url,而且能夠轉換request
  String requestKey = createKey(request);    //給請求建立了一個key
 if (shouldReadFromMemoryCache(memoryPolicy)) { 這裏默認是進去的
     Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); 先根據requestKey到cache裏找
    若是cache裏能找到,就取消請求,直接設置
    if (callback != null) {
          callback.onSuccess();
     }    //若是咱們以前傳callback進來的話,在成功設置圖片後,還能夠回調這個方法
    若是cache裏沒有找到的話,

  if (setPlaceholder) {

      setPlaceholder(target, getPlaceholderDrawable());

    }//看有沒有設置一個加載時默認顯示的圖片

    最重要的一行

Action action =
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);

    Action表明了一個具體的加載任務,裏面有complete和error方法,主要用於回調

    U最後

picasso.enqueueAndSubmit(action);
     void enqueueAndSubmit(Action action) {

    Object target = action.getTarget();        //這個target就是ImageView

    if (target != null && targetToAction.get(target) != action) {    //若是這個image以前尚未請求過

      // This will also check we are on the main thread.

      cancelExistingRequest(target);

      targetToAction.put(target, action);

    }

    submit(action);

  }

    if裏的,若是請求已經存在,則取消請求。從新放進去一遍

    最後提交

  void submit(Action action) {

    dispatcher.dispatchSubmit(action);

  }
   void dispatchSubmit(Action action) {

    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));

  }

   這時候這個Dispatcher就起到分發的做用。

  Dispatcher裏的handleMessage方法裏的

case REQUEST_SUBMIT: {

          Action action = (Action) msg.obj;

          dispatcher.performSubmit(action);

          break;

        }
void performSubmit(Action action) {
    performSubmit(action, true);
  }
  void performSubmit(Action action, boolean dismissFailed) {
    if (pausedTags.contains(action.getTag())) {
      pausedActions.put(action.getTarget(), action);
      if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
            "because tag '" + action.getTag() + "' is paused");
      }
      return;
    }
    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;
    }
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    hunter.future = service.submit(hunter);
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
      failedActions.remove(action.getTarget());
    }
    if (action.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
  }

 注意這裏的,hunter是一個Runnable,負責具體的加載,把最後加載的結果經過dispatcher分發出去

  if (result == null) {

        dispatcher.dispatchFailed(this);

      } else {

        dispatcher.dispatchComplete(this);

      }

這個是run方法裏的一小段代碼

相關文章
相關標籤/搜索