从Zero分析Picasso源码

Picasso 是 Square 开源的图片缓存库,主要特点有:

  • 包含内存缓存和磁盘缓存两级缓存。
  • 在 Adapter 中自动处理 ImageView 的缓存并且取消之前的图片下载任务。
  • 方便进行图片转换处理。

基本使用

Picasso.with(this)  //Context
        .load("http://7xjung.com1.z0.glb.clouddn.com/randomview.png") //图片地址
        .placeholder(R.drawable.abc_btn_check_material) //占位图(等待下载的图片)
        .error(R.drawable.abc_btn_radio_material) //加载错误显示的图片
        .resize(200,200) //设置显示大小
        .centerCrop()  //适应布局,减小内存
        .into(mLoadIv); //用来显示图片控件的ID

下载地址 : https://github.com/square/picasso

分析工作流程

分析第一次加载图片的情况,没有缓存。

Picasso.with(this):

  public static Picasso with(Context context) {
    if (singleton == null) {
      synchronized (Picasso.class) {  
        if (singleton == null) {
          singleton = new Builder(context).build();  //获取实例对象
        }
      }
    }
    return singleton;
  }
  //这里使用了单例模式,而且是双重检测锁的方法。 另外还使用到了Builder模式,Picasso对象的创建非常复杂。

得到的是context.getApplicationContext();

    public Builder(Context context) {
      if (context == null) {
        throw new IllegalArgumentException("Context must not be null.");
      }
      this.context = context.getApplicationContext();
    }

Picasso的部分成员变量

  private final Listener listener;
  private final RequestTransformer requestTransformer;
  private final CleanupThread cleanupThread;
  private final List<RequestHandler> requestHandlers;

  final Context context;
  final Dispatcher dispatcher;
  final Cache cache;
  final Stats stats;
  final Map<Object, Action> targetToAction;
  final Map<ImageView, DeferredRequestCreator> targetToDeferredRequestCreator;
  final ReferenceQueue<Object> referenceQueue;
  final Bitmap.Config defaultBitmapConfig;

看下build()方法,返回Picasso,初始化各种服务,下载器,缓存器,线程池,是否resize图片,调度器

 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时可以调用来修改请求)。

之后调用load(),有4个重载方法

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));  //调用load(Uri uri)
  }
public RequestCreator load(File file) {
    if (file == null) {
      return new RequestCreator(this, null, 0);
    }
    return load(Uri.fromFile(file)); //调用load(Uri uri)
  }
public RequestCreator load(int resourceId) {
    if (resourceId == 0) {
      throw new IllegalArgumentException("Resource ID must not be zero.");
    }
    return new RequestCreator(this, null, resourceId);
  }
public RequestCreator load(Uri uri) {
    return new RequestCreator(this, uri, 0);
  }

最终都是执行

new RequestCreator(this, uri, 0)

那么RequsetCreator是什么呢?(创造图片下载的请求)

private final Request.Builder data; //this.data

 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()方法,初始化

Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
  this.uri = uri;
  this.resourceId = resourceId;
  this.config = bitmapConfig;
}

之后是into()

  public void into(ImageView target) {
    into(target, null);
  }

关键在于下面这个方法:

  public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    checkMain(); //Looper.getMainLooper().getThread() == Thread.currentThread(),检查是不是主线程执行的。

    if (target == null) {
      throw new IllegalArgumentException("Target must not be null.");
    }

    if (!data.hasImage()) { //boolean hasImage() {return uri != null || resourceId != 0;},是否为空
      picasso.cancelRequest(target);
      if (setPlaceholder) {
        setPlaceholder(target, getPlaceholderDrawable());
      }
      return;
    }

    if (deferred) { //public RequestCreator fit() {deferred = true;return this;}判断是否改变图片大小,适配控件;deferred在这里是默认值false
      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); //这里创建了请求,给请求唯一的id,url,并且转换request
    String requestKey = createKey(request); //给请求创建了一个key

    if (shouldReadFromMemoryCache(memoryPolicy)) { //读取缓存
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        picasso.cancelRequest(target);//如果cache里能找到,就取消请求,直接设置
        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 = //Action是一个抽象类
        new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);

    picasso.enqueueAndSubmit(action);
  }

创建回调方法:下载完图片,再通过控件显示

  ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
      int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
      Callback callback, boolean noFade) {
    super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,
        tag, noFade);
    this.callback = callback;
  }

Action构造方法

  Action(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy,
      int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) {
    this.picasso = picasso;
    this.request = request;
    this.target =
        target == null ? null : new RequestWeakReference<T>(this, target, picasso.referenceQueue);
    this.memoryPolicy = memoryPolicy;
    this.networkPolicy = networkPolicy;
    this.noFade = noFade;
    this.errorResId = errorResId;
    this.errorDrawable = errorDrawable;
    this.key = key;
    this.tag = (tag != null ? tag : this);
  }
  // Action代表了一个具体的加载任务

Action中用了一个弱引用,创建请求队列

  static class RequestWeakReference<M> extends WeakReference<M> {
    final Action action;

    public RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
      super(referent, q);
      this.action = 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);  //  final Map<Object, Action> targetToAction;映射结构
    }
    submit(action);
  }

分给调度器执行任务(分发任务)

final Dispatcher dispatcher;

  void submit(Action action) {
    dispatcher.dispatchSubmit(action);
  }

发送到消息队列

  void dispatchSubmit(Action action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
  }

看下handler如何工作的?

    //Dispatcher构造方法的语句
  this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);

定义了一个静态内部类,执行不同的请求:

private static class DispatcherHandler extends Handler {
    private final Dispatcher dispatcher;

    public DispatcherHandler(Looper looper, Dispatcher dispatcher) {
      super(looper);
      this.dispatcher = dispatcher;
    }

    @Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case REQUEST_SUBMIT: {
          Action action = (Action) msg.obj;
          dispatcher.performSubmit(action);
          break;
        }
        ......//省略其它case
      }
    }
  }

请求REQUEST_SUBMIT之后的方法:

  void performSubmit(Action action) {
    performSubmit(action, true);
  }

  void performSubmit(Action action, boolean dismissFailed) {
    if (pausedTags.contains(action.getTag())) {
      pausedActions.put(action.getTarget(), action);  //  final Map<Object, Action> pausedActions;
      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());  //BitmapHunter实现了Runnable方法
    if (hunter != null) {
      hunter.attach(action);  //注意这个attach(),将action加入到一个List中,actions.add(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);  //交给线程池去执行, 初始化的PicassoExecutorService, <T> Future<T> submit(Runnable task, T result);
    hunterMap.put(action.getKey(), hunter);  //管理起来,防止任务重复
    if (dismissFailed) {
      failedActions.remove(action.getTarget());
    }

    if (action.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
  }

  //线程池中结合优先级去执行任务的,之前有设定Picasso类中的枚举类型Priority。

终于找到了图片加载的来源,就是BitmapHunter的run()执行的:

result = hunt()

下面是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;
      }
    }

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

      // If there was no Bitmap then we need to decode it from the stream.
      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;
  }

Picasso的Handler来处理接受到的消息(主线程中)

 static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
    @Override public void handleMessage(Message msg) {
      switch (msg.what) {
        case HUNTER_BATCH_COMPLETE: {
          @SuppressWarnings("unchecked") List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
          //noinspection ForLoopReplaceableByForEach
          for (int i = 0, n = batch.size(); i < n; i++) {
            BitmapHunter hunter = batch.get(i);
            hunter.picasso.complete(hunter);  //这里获取到result
          }
          break;
        }
        case REQUEST_GCED: {
          Action action = (Action) msg.obj;
          if (action.getPicasso().loggingEnabled) {
            log(OWNER_MAIN, VERB_CANCELED, action.request.logId(), "target got garbage collected");
          }
          action.picasso.cancelExistingRequest(action.getTarget());
          break;
        }
        case REQUEST_BATCH_RESUME:
          @SuppressWarnings("unchecked") List<Action> batch = (List<Action>) msg.obj;
          //noinspection ForLoopReplaceableByForEach
          for (int i = 0, n = batch.size(); i < n; i++) {
            Action action = batch.get(i);
            action.picasso.resumeAction(action);
          }
          break;
        default:
          throw new AssertionError("Unknown handler message received: " + msg.what);
      }
    }
  };

完成后是调用的ImageViewAction里的方法,

  @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);
    if (callback != null) {
      callback.onSuccess(); //调用回调方法
    }
  }

//关于线程池的分析又是一大波。。。暂时不贴上

主要涉及的类:Picasso,Request,RequestCreator, Action, ImageViewAction, Utils,Dispatcher, BitmapHunter…

参考

http://www.cnphp6.com/archives/87269

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值