2019-10-07

圖片加載框架Picasso源碼的簡(jiǎn)單分析(一)

本篇文章只是對(duì)Picasso加載流程做加單的分析,相對(duì)于其他常用的圖片框架Picasso算是比較精煉簡(jiǎn)潔。 但是即便再簡(jiǎn)單的圖片加載框架都會(huì)包含數(shù)據(jù)流讀取、內(nèi)存策略、尺寸剪裁等模塊, 一次性通篇分析完整個(gè)框架源碼內(nèi)容信息過多,不利于讀者快速閱讀和消化吸收。所以本篇就簡(jiǎn)單的說明。相關(guān)知識(shí)點(diǎn)會(huì)在其他相關(guān)博客中說明。

1. Picasso的總體流程:

Picasso使用采用鏈?zhǔn)降姆绞?,圖片的加載流程如下:

1)創(chuàng)建Picassco和RequestCreator對(duì)象, RequestCreator封裝了加載資源文件的來源。

2)RequestCreator將請(qǐng)求封裝為Request對(duì)象,然后創(chuàng)建Action對(duì)象(例如ImageViewAction)。

3)Picasso對(duì)象將action分發(fā)給Dispatcher對(duì)象,Dispatcher創(chuàng)建BitmapHunter, 同時(shí)將Action封裝到BitmapHunter,BitmapHunter是Runnable任務(wù)類。然后將BitmapHunter提交到線程池去執(zhí)行。

4)BitmapHunter調(diào)用RequestHandler來處理當(dāng)前request, 獲取數(shù)據(jù)流InputStream封裝到Result對(duì)象中。BitmapHunter通過Result獲取InputStream讀取解析出Bitmap對(duì)象。

5)BitmapHunter調(diào)用Dispatcher將自身回調(diào)到Picasso.complete()方法中,獲取Action對(duì)象。Action將生成的bitmap設(shè)置到ImageView中。

代碼時(shí)序圖如下:

Picasso加載時(shí)序圖.png

2. 相關(guān)類的作用和創(chuàng)建過程以圖片獲取過程

2.1 Picasso對(duì)象的創(chuàng)建過程

Picasso創(chuàng)建采用Builder建造者模式創(chuàng)建單例, 代碼如下:

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

Builder模式的優(yōu)點(diǎn)在于開發(fā)者可以通過配置組件的方法來創(chuàng)建對(duì)象實(shí)例,Picasso.Builder類的定義如下:

public static class Builder {
    private final Context context;                // APP全局上下文Contxt
    private Downloader downloader;                //自定義現(xiàn)下載管理類
    private ExecutorService service;              //線程池
    private Cache cache;                          //自定義緩存
    private Listener listener;  
    private RequestTransformer transformer;      //圖片尺寸裁剪類
    private List<RequestHandler> requestHandlers;//圖片實(shí)際下載處理類
    private Bitmap.Config defaultBitmapConfig;

Builder的build方法利用上面的默認(rèn)配置類定義和創(chuàng)建Picasso對(duì)象實(shí)例, 代碼如下:

public Picasso build() {
       。。。。。。。。
      if (downloader == null) {
        //創(chuàng)建默認(rèn)下載管理器
        downloader = Utils.createDefaultDownloader(context);
      }
      if (cache == null) {
        //創(chuàng)建默認(rèn)緩存
        cache = new LruCache(context);
      }
      if (service == null) {
        //創(chuàng)建默認(rèn)線程池
        service = new PicassoExecutorService();
      }
      if (transformer == null) {
        //創(chuàng)建默認(rèn)轉(zhuǎn)化器
        transformer = RequestTransformer.IDENTITY;
      }
      //創(chuàng)建請(qǐng)求分發(fā)調(diào)度管理器
      Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
      //根據(jù)前面創(chuàng)建的各種默認(rèn)組件封裝Picasso對(duì)象
      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }

2.2 RequestCreator

RequestCreator作用是根求請(qǐng)求的數(shù)據(jù)來源類型創(chuàng)建和封裝Requst和Action對(duì)象。Picasso對(duì)象在load()方法中創(chuàng)建RequestCreator對(duì)象。RequestCreator對(duì)象的into()方法中創(chuàng)建Requst和Action對(duì)象。

public class RequestCreator {
 。。。。。。
  private final Picasso picasso;         //Picasso對(duì)象實(shí)例 
  private final Request.Builder data;    //Request Builder構(gòu)造器,用于生成Request
  。。。。。。
  }

Picasso在load方法中直接通過new的方式生成RequestCreator對(duì)象。RequestCreator構(gòu)造方法如下:

RequestCreator(Picasso picasso, Uri uri, int resourceId) {
    //Picasso實(shí)例對(duì)象
    this.picasso = picasso;            
    //生成Request對(duì)象構(gòu)造器
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);    
  }

RequestCreator對(duì)象的into()方法中生成Request和Action對(duì)象

public void into(ImageView target, Callback callback) {
    //創(chuàng)建Request對(duì)象
    Request request = createRequest(started);
    //生成requestKey,用于索引查找
    String requestKey = createKey(request);
    if (shouldReadFromMemoryCache(memoryPolicy)) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        //如果通過所以查找到內(nèi)存中存在已經(jīng)生成的bitmap對(duì)象,直接返回,不做進(jìn)一步操作
        picasso.cancelRequest(target);
        setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
        return;
      }
    }
    //創(chuàng)建Action對(duì)象
    Action action =
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);
    //將Action通過Picasso對(duì)象分發(fā)給Dispathcer對(duì)象
    picasso.enqueueAndSubmit(action);
  }

2.3 Dispatcher

Dispatcher類的主要作用是講Action對(duì)象封裝到BitmapHunter中。同事將 BitmapHunter對(duì)象提交到線程池執(zhí)行,BitmapHunter是Runnable類型任務(wù)執(zhí)行類。performSubmit()方法用于獲取BitmapHunter對(duì)象并提交到線程池中:

void performSubmit(Action action, boolean dismissFailed) {
    。。。。。。
    創(chuàng)建BitmapHunter對(duì)象
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    //BitmapHunter對(duì)象提交到線程池執(zhí)行
    hunter.future = service.submit(hunter);
    。。。。。。
  }

BitmapHunter對(duì)象實(shí)際在forRequest()方法中創(chuàng)建, forRequest()從Action中獲取Request,從Picasso對(duì)象中獲取圖片源處理組件封裝到BitmapHunter中。 代碼如下:

static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
      Action action) {
    //從Action中獲取Request對(duì)象
    Request request = action.getRequest();
    //獲取圖片源處理組件
    List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
    //創(chuàng)建BitmapHunter對(duì)象實(shí)例
    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
  }

2.4 BitmapHunter

BitmapHunter類, 實(shí)際處理圖片數(shù)據(jù)請(qǐng)求和生成Bitmap的關(guān)鍵類,核心方法是hunt()防范,線程執(zhí)行入口方法通過hunt()獲取Bitmap對(duì)象,并回調(diào)給Dispathcer對(duì)象。run()方法執(zhí)行代碼如下:

public void run() {
      //獲取Bitmap對(duì)象
      result = hunt();
      //通過Dispatcher回調(diào)成功獲取bitmap
      dispatcher.dispatchComplete(this);
}

hunt()方法

Bitmap hunt() throws IOException {
    。。。。。
    //通過RequestHandler對(duì)象獲取文件數(shù)據(jù)流InputStream,并把InputStream封裝到Result中。
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    //從Result中獲取文件數(shù)據(jù)流
    InputStream is = result.getStream();
    try {
         //生成Bitmap對(duì)象實(shí)例
         bitmap = decodeStream(is, data);
     } finally {
         Utils.closeQuietly(is);
     }
    //返回對(duì)象實(shí)例
    return bitmap;
    。。。。。。
  }

2.5RequestHandler

RequestHandler類的作用是根據(jù)不同類型的圖片數(shù)據(jù)來源(網(wǎng)絡(luò)、文件、資源文件等)獲取想對(duì)應(yīng)的InputStram,封裝到Result中。以AssetRequestHandler為例,執(zhí)行代碼如下:

public Result load(Request request, int networkPolicy) throws IOException {
    //獲取Asset中資源文件的文件流InputStream
    InputStream is = assetManager.open(getFilePath(request));
    //將圖片文件流InputStream封裝到Result中,并返回。
    return new Result(is, DISK);
  }

3. Bitmap獲取后回調(diào)和加載過程

上面2.4 BitmapHunter節(jié)中介紹到Bitmap圖像獲取后會(huì)通過Dispatcher對(duì)象實(shí)例回調(diào),最終會(huì)回調(diào)到Picasso方法complete()中。代碼如下:

void complete(BitmapHunter hunter) {
    //獲取Action對(duì)象
    Action single = hunter.getAction();
    //獲取Bitmap對(duì)象
    Bitmap result = hunter.getResult();
    if (single != null) {
      //將Bitmap對(duì)象交給Action對(duì)象處理
      deliverAction(result, from, single);
    }
  }

3.1 Action

Action類的作用是圖片Bitmap對(duì)象獲取成功后,將Bitmap對(duì)象設(shè)置到ImageView中。其核心方法是complete()房,代碼如下:

public void complete(Bitmap result, Picasso.LoadedFrom from) {
    。。。。。。
    //從Action中獲取ImageView對(duì)象
    ImageView target = this.target.get();
    //獲取上下文實(shí)例
    Context context = picasso.context;
    //通過PicassoDrawable將Bitmap設(shè)置到ImageView中
    PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);

    if (callback != null) {
       //圖片加載成功回調(diào)
      callback.onSuccess();
    }
    。。。。。。
  }

本片文章根據(jù)時(shí)序流程介紹了Picasso圖片數(shù)據(jù)請(qǐng)求過程和加載過程,由于篇幅原因具體實(shí)現(xiàn)細(xì)節(jié)無法仔細(xì)說明,后面的章節(jié)會(huì)逐步更新相關(guān)代碼分析。

?著作權(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)容

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