1. 程式人生 > >Android框架原始碼解析之(四)Picasso

Android框架原始碼解析之(四)Picasso

Picasso

這次要分析的原始碼是 Picasso 2.5.2 ,四年前的版本,用eclipse寫的,但不影響這次我們對其原始碼的分析
地址:https://github.com/square/picasso/tree/picasso-parent-2.5.2

Picasso的簡單使用

 Picasso.with(this)
        .load("http://ww3.sinaimg.cn/large/610dc034jw1fasakfvqe1j20u00mhgn2.jpg")
        .into(mImageView);

清晰簡潔

Picasso的原始碼分析

首先看一下基本流程
Picasso基本流程

Picasso的總體流程:
1)將請求封裝為Request物件,然後將Request物件進一步封裝為Action(ImageAction)物件。
2)將Action(ImageAction)物件交給Dispather進行分發
3)最終將action交給BitmapHunter這個Runnable作為線上程池中執行緒的工作的單元(具體的是講action持有的當前Reqeuest物件)
4)由RequestHandler來處理當前request,呼叫其load方法將載入完成後的圖片交給PicassoDrawable顯示圖片。
程式碼流程如下:Picasso->load->建立request->建立action->Dispatcher分發action->RequestHandler的load方法處理具體的請求->PicassoDrawable顯示圖片。

下面來看細節:

1、Picasso.with()
首先看一下Picasso的構造方法

  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; // Adjust this as internal handlers are added or removed.
	
	//使用者自定義RequestHandler的數量
    int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
    List<RequestHandler> allRequestHandlers =
        new ArrayList<RequestHandler>(builtInHandlers + extraCount);

	//新增各種RequestHandler
		
	//先新增ResourceRequestHandler
		
		
    // ResourceRequestHandler needs to be the first in the list to avoid
    // forcing other RequestHandlers to perform null checks on request.uri
    // to cover the (request.resourceId != 0) case.
    allRequestHandlers.add(new ResourceRequestHandler(context));
    if (extraRequestHandlers != null) {
      allRequestHandlers.addAll(extraRequestHandlers);
    }
    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.stats = stats;
    this.targetToAction = new WeakHashMap<Object, Action>();
    this.targetToDeferredRequestCreator = new WeakHashMap<ImageView, DeferredRequestCreator>();
    this.indicatorsEnabled = indicatorsEnabled;
    this.loggingEnabled = loggingEnabled;
    this.referenceQueue = new ReferenceQueue<Object>();
    this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
    this.cleanupThread.start();
  }

with()函式通過雙重檢查鎖模式返回預設Picasso預設例項

   //通過雙重檢查鎖模式  返回Picasso單例物件
  public static Picasso with(Context context) {
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
        
        //通過建造者模式,對Picasso進行系統預設設定
        
          singleton = new Builder(context).build();
        }
      }
    }
    return singleton;
  }

通過建造者模式,對Picasso進行系統預設設定

  /** Fluent API for creating {@link Picasso} instances. */
  @SuppressWarnings("UnusedDeclaration") // Public API.
  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;//配置RequestHandler 集合
    private Bitmap.Config defaultBitmapConfig;//配置預設圖片設定

    private boolean indicatorsEnabled;
    private boolean loggingEnabled;

    /** Start building a new {@link Picasso} instance. */
    public Builder(Context context) {
      if (context == null) {
        throw new IllegalArgumentException("Context must not be null.");
      }
      this.context = context.getApplicationContext();
    }

    /**
     * Specify the default {@link Bitmap.Config} used when decoding images. This can be overridden
     * on a per-request basis using {@link RequestCreator#config(Bitmap.Config) config(..)}.
     */
    public Builder defaultBitmapConfig(Bitmap.Config bitmapConfig) {
      if (bitmapConfig == null) {
        throw new IllegalArgumentException("Bitmap config must not be null.");
      }
      this.defaultBitmapConfig = bitmapConfig;
      return this;
    }

    /** Specify the {@link Downloader} that will be used for downloading images. */
    public Builder downloader(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;
    }

    /**
     * Specify the executor service for loading images in the background.
     * <p>
     * Note: Calling {@link Picasso#shutdown() shutdown()} will not shutdown supplied executors.
     */
    public Builder executor(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;
    }

    /** Specify the memory cache used for the most recent images. */
    public Builder memoryCache(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;
    }

    /** Specify a listener for interesting events. */
    public Builder listener(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;
    }

    /**
     * Specify a transformer for all incoming requests.
     * <p>
     * <b>NOTE:</b> This is a beta feature. The API is subject to change in a backwards incompatible
     * way at any time.
     */
    public Builder requestTransformer(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;
    }

    /** Register a {@link RequestHandler}. */
    public Builder addRequestHandler(RequestHandler requestHandler) {
      if (requestHandler == null) {
        throw new IllegalArgumentException("RequestHandler must not be null.");
      }
      if (requestHandlers == null) {
        requestHandlers = new ArrayList<RequestHandler>();
      }
      if (requestHandlers.contains(requestHandler)) {
        throw new IllegalStateException("RequestHandler already registered.");
      }
      requestHandlers.add(requestHandler);
      return this;
    }

    /**
     * @deprecated Use {@link #indicatorsEnabled(boolean)} instead.
     * Whether debugging is enabled or not.
     */
    @Deprecated public Builder debugging(boolean debugging) {
      return indicatorsEnabled(debugging);
    }

    /** Toggle whether to display debug indicators on images. */
    public Builder indicatorsEnabled(boolean enabled) {
      this.indicatorsEnabled = enabled;
      return this;
    }

    /**
     * Toggle whether debug logging is enabled.
     * <p>
     * <b>WARNING:</b> Enabling this will result in excessive object allocation. This should be only
     * be used for debugging purposes. Do NOT pass {@code BuildConfig.DEBUG}.
     */
    public Builder loggingEnabled(boolean enabled) {
      this.loggingEnabled = enabled;
      return this;
    }

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

可以看出with()函式主要 使用單例模式(雙重檢查鎖)建立Picasso例項,並使用建造者模式 對Picasso進行初始化配置。

2、Picasso.load()

 //建立RequestCreator
  public RequestCreator load(Uri uri) {
    return new RequestCreator(this, uri, 0);
  }

  /**
   * Start an image request using the specified path. This is a convenience method for calling
   * {@link #load(Uri)}.
   * <p>
   * This path may be a remote URL, file resource (prefixed with {@code file:}), content resource
   * (prefixed with {@code content:}), or android resource (prefixed with {@code
   * android.resource:}.
   * <p>
   * Passing {@code null} as a {@code path} will not trigger any request but will set a
   * placeholder, if one is specified.
   *
   * @see #load(Uri)
   * @see #load(File)
   * @see #load(int)
   * @throws IllegalArgumentException if {@code path} is empty or blank string.
   */
  public RequestCreator load(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));
  }

  /**
   * Start an image request using the specified image file. This is a convenience method for
   * calling {@link #load(Uri)}.
   * <p>
   * Passing {@code null} as a {@code file} will not trigger any request but will set a
   * placeholder, if one is specified.
   * <p>
   * Equivalent to calling {@link #load(Uri) load(Uri.fromFile(file))}.
   *
   * @see #load(Uri)
   * @see #load(String)
   * @see #load(int)
   */
  public RequestCreator load(File file) {
    if (file == null) {
      return new RequestCreator(this, null, 0);
    }
    return load(Uri.fromFile(file));
  }

  /**
   * Start an image request using the specified drawable resource ID.
   *
   * @see #load(Uri)
   * @see #load(String)
   * @see #load(File)
   */
  public RequestCreator load(int resourceId) {
    if (resourceId == 0) {
      throw new IllegalArgumentException("Resource ID must not be zero.");
    }
    return new RequestCreator(this, null, resourceId);
  }

可以看出這幾種過載方法 目的都是為了建立RequestCreator 物件

//讓我們來看看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;
//接著建立了Request物件
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
  }

呼叫load方法的時候實際上並沒有對圖片資源進行載入,只是簡單返回了一個RequestCreator物件,該物件在初始化的時候初始化了Request的Builder物件

3、RequestCreator.into()
使用過Picasso的都知道,我們呼叫RequestCreator的into方法來完成工作的,那麼就先簡單的分析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 request = createRequest(started);
	//建立請求的key
    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,實際上是一個ImageViewAction

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

			
	//提交Action
    picasso.enqueueAndSubmit(action);
  }

繼續檢視 picasso.enqueueAndSubmit(action)

  void enqueueAndSubmit(Action action) {
    Object target = action.getTarget();
    if (target != null && targetToAction.get(target) != action) {
      // This will also check we are on the main thread.
      cancelExistingRequest(target);
      targetToAction.put(target, action);
    }
    submit(action);
  }

  void submit(Action action) {
//重點在這
    dispatcher.dispatchSubmit(action);
  }

繼續跟進 dispatcher.dispatchSubmit(action);

  void dispatchSubmit(Action action) {
    
    //這裡呼叫了handler傳送訊息
     

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


    @Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case REQUEST_SUBMIT: {
          Action action = (Action) msg.obj;

//重點在這
          dispatcher.performSubmit(action);
          break;
        }

繼續跟進dispatcher.performSubmit(action);

  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獲取了請求的key,Hunter是一個runnable
    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;
    }
	
	
	//重點在這   forRequest();

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

繼續跟進forRequest();

static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
      Action action) {
    //獲取當前請求物件
    Request request = action.getRequest();
    //獲取picasso內建的RequestHandler物件和自定義的RequestHandler物件
    List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
    //判斷內建物件或者自定義的物件哪一個物件能處理當前請求
    for (int i = 0, count = requestHandlers.size(); i < count; i++) {
      RequestHandler requestHandler = requestHandlers.get(i);
      if (requestHandler.canHandleRequest(request)) {//如果能處理當前請求
        //返回一個bitMapHandler
        //把當前ReqeuestHandler物件交給BitmapHunter
        return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
      }
    }
    //說明當前請求無效
    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
  }

上面forRequest方法也很簡單:主要執行了一下邏輯
1、獲取當前請求Reqeuest物件
2、獲取Picasso內建的RequestHandler以及自定義的RequestHandler集合。
3、判斷集合中哪一個RequestHandler物件可以對當前Reqeuest進行處理(canHanlderReqest返回true)
4、把集合中能處理當前Request的RequestHandler物件交給BitMapHunter。

Action的簡單說明:
Action所有的屬性如下:

final Picasso picasso;//持有上文單利引用
  final Request request;//上文提到的request
  final WeakReference<T> target;//target可能是ImageView,或者優先理解為ImageView,為弱引用,確保target被回收的時候不受影響
  final boolean noFade;
  final int memoryPolicy;//快取策略
  final int networkPolicy;//
  final int errorResId;
  final Drawable errorDrawable;
  final String key;
  final Object tag;
  boolean willReplay;
  boolean cancelled;

Action的主要職責就是:對圖片進行載入,配置圖片的檔案快取和記憶體快取策略以及是否重新載入等邏輯。使得責任分明,調理清晰。

Action是一個抽象的泛型類,提供了complete和error兩個抽象方法

  abstract void complete(Bitmap result, Picasso.LoadedFrom from);

  abstract void error();

它的子類又如下幾個:
GetAction、FetchAction、ImageViewAction、TargetAction在此處我們提交的是ImageViewAction.
讓我們簡單的看一下ImageViewAction的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);

	//設定callback
    if (callback != null) {
      callback.onSuccess();
    }
  }

可以發現最終是由PicassoDrawable來完成圖片的顯示,所以繼續跟進:
PicasDrawable是BitmapDrawable的子類:

final class PicassoDrawable extends BitmapDrawable {
  static void setBitmap(ImageView target, Context context, Bitmap bitmap,
      Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
      //獲取drawable
    Drawable placeholder = target.getDrawable();
    if (placeholder instanceof AnimationDrawable) {
      ((AnimationDrawable) placeholder).stop();
    }
    //建立
    PicassoDrawable drawable =
        new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
        //顯示
    target.setImageDrawable(drawable);
  }
//最終將圖片顯示出來
}

RequestHandler
該類用來處理不同來源的圖片,是個抽象類。
在picasso只是用面向物件的方式處理來自網路(NetworkRequestHandler),Resoure資源圖片(ResourceRequestHandler),asset檔案中的圖片(AssetRequestHandler)等等若干個Handler。在初始化Picasso的時候,Picasso預設實現的RequestHandler的上述子類是預載入到一個集合中去的!

Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
      RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
      Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {


...........................

/使用者自定義RequestHandler的數量
    int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
    List<RequestHandler> allRequestHandlers =
        new ArrayList<RequestHandler>(builtInHandlers + extraCount);

	//新增各種RequestHandler
		
	//先新增ResourceRequestHandler
		
		
    // ResourceRequestHandler needs to be the first in the list to avoid
    // forcing other RequestHandlers to perform null checks on request.uri
    // to cover the (request.resourceId != 0) case.
    allRequestHandlers.add(new ResourceRequestHandler(context));
    if (extraRequestHandlers != null) {
      allRequestHandlers.addAll(extraRequestHandlers);
    }
    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);



}

Picasso自己實現的handler在構造器初始化的時候就把自己實現的RequestHander的子類預先初始化好(姑且稱之為Picasso內建的ReqeustHandler物件),當然使用者也可以實現自己的RequestHandler通過Picasso.Builder.addRequestHandler來新增進去,當然大多數情況不需要自己提供ReqeuestHandler的實現。

那Picasso怎麼知道是來自於哪個種類的圖片呢?這就是ReqeuestHandler的功能了!RequestHandler時候一個抽象類,從名字上就可以知道它是處理具體請求的,它提供了兩個重要的抽象方法來完成對不同種類圖片的處理工作:

  /**
   * Whether or not this {@link RequestHandler} can handle a request with the given {@link Request}.
   */
//判斷某子類是否有能力處理當前請求 
  public abstract boolean canHandleRequest(Request data);

  /**
   * Loads an image for the given {@link Request}.
   *
   * @param request the data from which the image should be resolved.
   * @param networkPolicy the {@link NetworkPolicy} for this request.
   * 
   */
//在canHandleRequest方法返回true的時候,就用該RequestHandler的實現類的load方法來載入圖片!
  public abstract Result load(Request request, int networkPolicy) throws IOException;

簡單分析一下
Picasso怎麼處理網路Reqeust的:NetworkRequestHandler

//判斷當前請求的圖片資源是否來自於伺服器或者網路
public boolean canHandleRequest(Request data) {
    String scheme = data.uri.getScheme();
    return (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme));
  }
//NetWorkReqesutHandler對load的處理  
public Result load(Request request, int networkPolicy) throws IOException {
    //下載圖片資源,返回一個Response物件
    Response response = downloader.load(request.uri, request.networkPolicy);
    if (response == null) {
      return null;
    }

    Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;
    Bitmap bitmap = response.getBitmap();
    if (bitmap != null) {
      return new Result(bitmap, loadedFrom);
    }

    InputStream is = response.getInputStream();
    if (is == null) {
      return null;
    }
     。。。此處有省略程式碼。。。
    return new Result(is, loadedFrom);
  }

Picasso怎麼處理ResourceReqeust的:ResourceRequestHandler

  @Override
   public boolean canHandleRequest(Request data) {
	  //若資源id不為0,則判斷為為Resource,能載入
    if (data.resourceId != 0) {
      return true;
    }

	//判斷檔案scheme是否為 RESOURCE
    return SCHEME_ANDROID_RESOURCE.equals(data.uri.getScheme());
  }

  @Override
   public Result load(Request request, int networkPolicy) throws IOException {
	  //載入Resource檔案(R檔案引用)
    Resources res = Utils.getResources(context, request);
    int id = Utils.getResourceId(res, request);
    return new Result(decodeResource(res, id, request), DISK);
  }

Picasso怎麼處理FileReqeust的:FileRequestHandler

  @Override public boolean canHandleRequest(Request data) {
    //判斷檔案scheme是否為FILE
	return SCHEME_FILE.equals(data.uri.getScheme());
  }

  @Override public Result load(Request request, int networkPolicy) throws IOException {
    return new Result(null, getInputStream(request), DISK, getFileExifRotation(request.uri));
  }

其他檔案來源均類似

注意此時Picasso並沒有立即呼叫RequestHandler物件的load方法進行處理,而是繼續呼叫 service.submit(hunter);方法來線上程池中對BitmapHunter這個Runnable進行處理,所以我們不難猜測出來在run方法中必然呼叫了RequestHandler的load方法!

那麼就繼續追蹤BimapHunter的run方法發現其呼叫了hunt()方法,那麼hunt()方法是由做了什麼

//BitmapHunter的run方法
public void run() { 
    result = hunt();//獲取執行結果
 }
//注意該方法返回了一個bitmap
 Bitmap hunt() throws IOException {
    Bitmap bitmap = null;

    //獲取讀取記憶體程式碼省略
    data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    //此處真是呼叫了load方法進行處理
    RequestHandler.Result result = requestH andler.load(data, networkPolicy);
     ....此處省略大量程式碼....
    return bitmap;
  }

在hunt()方法中正式呼叫了forReqeuset過濾的ReqesutHandler物件的load方法完成了核心業務功能!

在這裡插入圖片描述

上面簡單的介紹了一下Picasso的工作流程,,希望能對大家有所幫助~~~