(Android)Picasso图片处理框架简要分析 1

Square公司开源的图片加载库。优点是功能还算完善,能满足基本的图片加载需求,使用简单,体量小。
官方链接: http://square.github.io/picasso/

Git: https://github.com/square/picasso

本篇文章基于Picasso 2.71828,从基本的使用一步步分析

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

从get()方法来看,这个版本的Picasso和之前有所修改,之前用过的同学应该知道,之前是采用的with()方法

 public static Picasso get() {
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
          if (PicassoProvider.context == null) {
            throw new IllegalStateException("context == null");
          }
          singleton = new Builder(PicassoProvider.context).build();
        }
      }
    }
    return singleton;
  }

上面的代码用了一个Double Check的同步锁,singleton是volatile类型的,构造了一个Picasso对象,接着看PicassoProvider,这个类继承于ContentProvider,在onCreate方法中用getContext()获取了Context。然后看build方法

** Create the {@link Picasso} instance. */
    public Picasso build() {
      Context context = this.context;

      if (downloader == null) {
        downloader = new OkHttp3Downloader(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);
    }
  }

方法的注释写了,这个方法是创建Picasso的instance,这里面构造了

downloader :负责图片的实际加载

cache:内存缓存,LruCache,看过它源码的同学应该知道,他由LinkedHashMap实现,里面实际上是一个双向链表,每次修改会把最新的对象放到链表尾端,当链表达到最大长度,就会删除链表头的元素,这样就可以保留最近被使用的对象

service:Picasso的线程池

PicassoExecutorService() {
    super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
        new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
  }
DEFAULT_THREAD_COUNT=3,核心线程数和最大线程都是3个,提交的阻塞队列为具有优先级的无界队列队列,blockingQueue的实现原理就是Lock配合Full和Empty两个信号量,对队列进行操作的。

transformer:请求转换器

Stats:表示缓存的状态,Bitmap和download的状态

dispatcher:请求分发器,很重要,后面的文章分析。

扫描二维码关注公众号,回复: 1552973 查看本文章

load方法

public RequestCreator load(@Nullable 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方法直接返回了一个RequestCreator,这个类是用来加载请求的,这里会创建一个Request builder对象,传入了图片的Uri,resourceId,以及BitmapConfig。返回了一个RequestCreator,方便链式调用。这个类还可以设置placeHolder,error等参数。

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

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

首先会检测是否在主线程运行,通过getMainLooper的Thread去判断的。

  static boolean isMain() {
    return Looper.getMainLooper().getThread() == Thread.currentThread();
  }

接着判断图片信息和target是否为null,否则取消请求。

接着判断是否需要取缓存,取到了缓存就取消请求

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

这里两次提到了取消请求,我们看一下他是怎么做的

void cancelExistingRequest(Object target) {
    checkMain();
    Action action = targetToAction.remove(target);
    if (action != null) {
      action.cancel();
      dispatcher.dispatchCancel(action);
    }
    if (target instanceof ImageView) {
      ImageView targetImageView = (ImageView) target;
      DeferredRequestCreator deferredRequestCreator =
          targetToDeferredRequestCreator.remove(targetImageView);
      if (deferredRequestCreator != null) {
        deferredRequestCreator.cancel();
      }
    }
  }

这里在检测主线程后,出现了一个Action类,Action可以看做单个图片加载的任务model,抽象类。是一个Request的包装类。

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

targetToAction是一个Map,key为imageView,value为Action,取消请求时首先会移除这个值。然后在cancle dispatcher,这里面也是通过handler message来实现的,看到具体的实现

 void performCancel(Action action) {
    String key = action.getKey();
    BitmapHunter hunter = hunterMap.get(key);
    if (hunter != null) {
      hunter.detach(action);
      if (hunter.cancel()) {
        hunterMap.remove(key);
        if (action.getPicasso().loggingEnabled) {
          log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId());
        }
      }
    }

    if (pausedTags.contains(action.getTag())) {
      pausedActions.remove(action.getTarget());
      if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId(),
            "because paused request got canceled");
      }
    }

    Action remove = failedActions.remove(action.getTarget());
    if (remove != null && remove.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_CANCELED, remove.getRequest().logId(), "from replaying");
    }
  }

这里又出现了一个新类,BitmaoHunter,这是一个Runnable,用来开启线程下载,同时还可以解码图片,重点关注hunt方法,这里面会调用RequestHandler去下载图片,RequestHandler是一个抽象类,我们可以看NetworkRequestHandler中的load方法,这里会调用OkHttp去下载图片。

接着回去看CancelRequest的下半部分

if (target instanceof ImageView) {
      ImageView targetImageView = (ImageView) target;
      DeferredRequestCreator deferredRequestCreator =
          targetToDeferredRequestCreator.remove(targetImageView);
      if (deferredRequestCreator != null) {
        deferredRequestCreator.cancel();
      }
    }

这里有一个DeferredRequestCreator类,这个类会对我们的target(ImageView)进行监听,它用来辅助获取我们ImageView的宽和高,然后就会重新执行请求创建。这里我们同样需要remove掉这里面的记录。

这篇就暂时先到这里,后面我们继续分析Dispatcher和into后面的部分。


猜你喜欢

转载自blog.csdn.net/zhouy1989/article/details/80616286