Picasso代碼初探

Picasso代碼初探

簡(jiǎn)介

Picasso是square開(kāi)源的一個(gè)Android網(wǎng)絡(luò)圖片處理的庫(kù),鑒于使用過(guò)okHttp、Retrofit等square的NB庫(kù),因此打算嘗試下Picasso,了解下Picasso的NB之處。

使用

Picasso使用的語(yǔ)法與Glide一樣,或者說(shuō)Glide與Picasso一樣...

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

代碼的解讀也主要基于上面這行代碼。

代碼查看

with方法

通過(guò)上述代碼可以看出Picasso加載圖片的代碼使用構(gòu)造器模式,通過(guò)鏈?zhǔn)絺鬟fPicasso單例。首先查看Picasso類中的with方法:

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

with方法為Picasso類的靜態(tài)方法,通過(guò)構(gòu)造器返回Picasso的全局單例。

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

通過(guò)build方法代碼可以看出,Picasso實(shí)例包含許多內(nèi)容,下載器、緩存、服務(wù)、請(qǐng)求發(fā)送等。下面一步一步的來(lái)看這幾個(gè)實(shí)體:

  1. downloader
  2. cache
  3. service
  4. transformer

downloader

通過(guò)反射判斷使用OkHttpLoaderCreator或者UrlConnectionDownloader,通過(guò)OkHttpLoaderCreator建立的downloader還會(huì)通過(guò)getCacheDir方法獲取緩存路徑建立文件名為“picasso-cache”的Picasso的緩存文件。其中OkHttpDownloader為通過(guò)OkHttp請(qǐng)求來(lái)下載網(wǎng)絡(luò)圖片的類,具體內(nèi)容體現(xiàn)在后面講述的load方法中。

cache

緩存默認(rèn)使用LRU算法,即least-recently used,近期最少使用算法。首先在LruCache的構(gòu)造函數(shù)中計(jì)算出一個(gè)合理的大小,作為緩存的最大空間。

static int calculateMemoryCacheSize(Context context) {
    ActivityManager am = getService(context, ACTIVITY_SERVICE);
    boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
    int memoryClass = am.getMemoryClass();
    if (largeHeap && SDK_INT >= HONEYCOMB) {
      memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
    }
    // Target ~15% of the available heap.
    return 1024 * 1024 * memoryClass / 7;
  }

使用可用內(nèi)存堆的1/7作為圖片緩存(不清楚這個(gè)大小有啥依據(jù)沒(méi)有,本以為應(yīng)該給更多空間)。關(guān)于具體內(nèi)存大小,與Android系統(tǒng)配置相關(guān),我參考的是這篇博客

service

PicassoExecutorService實(shí)現(xiàn)Picasso線程池,構(gòu)造函數(shù)中實(shí)例化工作隊(duì)列和線程工廠。

transformer

RequestTransformer,請(qǐng)求在被執(zhí)行前經(jīng)過(guò)一層轉(zhuǎn)換。

stat

通過(guò)Stat標(biāo)記緩存的狀態(tài)(命中數(shù)、未命中數(shù)、總大小、平均大小、下載次數(shù)等)

dispatcher

分發(fā)處理事件,如圖片加載完成、請(qǐng)求提交、請(qǐng)求取消等。

load方法

通過(guò)傳遞的String返回RequestCreator,代碼如下:

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;
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
  }

Request同樣使用Builder模式進(jìn)行構(gòu)建,設(shè)置基本參數(shù)。

into方法

public void into(Target target) {
    long started = System.nanoTime();
    checkMain();

    if (target == null) {
      throw new IllegalArgumentException("Target must not be null.");
    }
    if (deferred) {
      throw new IllegalStateException("Fit cannot be used with a Target.");
    }

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

into方法首先進(jìn)行一系列的校驗(yàn),如是否是在主(UI)線程,目標(biāo)ImageView是否為空,URI或ResourceId是否為空等。經(jīng)過(guò)校驗(yàn)后,建立請(qǐng)求,并通過(guò)請(qǐng)求生成一個(gè)requestKey,該Key即為緩存中緩存該圖片的Key值,請(qǐng)求網(wǎng)絡(luò)前先通過(guò)該Key檢查圖片是否在緩存中。否則將請(qǐng)求加入Picasso的請(qǐng)求隊(duì)列中。

核心類為Dispatcher,通過(guò)DispatcherThread和BitmapHunter進(jìn)行整個(gè)工作隊(duì)列和Bitmap緩存等的管理。


Android開(kāi)發(fā)新手,若有錯(cuò)誤請(qǐng)指出,謝謝~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容