码迷,mamicode.com
首页 > 其他好文 > 详细

picasso的源码分析(一)

时间:2015-05-11 09:12:53      阅读:527      评论:0      收藏:0      [点我收藏+]

标签:

picasso的使用非常简单。我们只需要一行代码就够

picasso.with(context).load(uri).into(imageView);

先看with方法

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

这里使用了单例模式,而且是双重检测锁的方法。 另外还使用到了Builder模式,因为Picasso对象的创建非常复杂

我们直接看build方法

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

    接下来是Stats stats = new Stats(cache).

    可以看下这里类里面的主要的成员变量

    

final HandlerThread statsThread;
  final Cache cache;
  final Handler handler;
  long cacheHits;
  long cacheMisses;
  long totalDownloadSize;
  long totalOriginalBitmapSize;
  long totalTransformedBitmapSize;
  long averageDownloadSize;
  long averageOriginalBitmapSize;
  long averageTransformedBitmapSize;
  int downloadCount;
  int originalBitmapCount;
  int transformedBitmapCount;

    主要为了记录一些缓存的命中次数,下载的文件大小,下载次数,原始文件大小等等信息,暂时先不看是干什么用的

    这里有一个Handler,是做什么用的呢?比如Picasso请求一个之前已经请求过,现在已经被缓存过的图片,这时候在访问它就是命中了,这时候可以调用 stats.dispatchCacheHit();

 void dispatchCacheHit() {

    handler.sendEmptyMessage(CACHE_HIT);

  }
@Override public void handleMessage(final Message msg) {

      switch (msg.what) {

        case CACHE_HIT:

          stats.performCacheHit();

          break;

        case CACHE_MISS:

          stats.performCacheMiss();

          break;

        case BITMAP_DECODE_FINISHED:

          stats.performBitmapDecoded(msg.arg1);

          break;

        case BITMAP_TRANSFORMED_FINISHED:

          stats.performBitmapTransformed(msg.arg1);

          break;

        case DOWNLOAD_FINISHED:

          stats.performDownloadFinished((Long) msg.obj);

          break;

        default:

          Picasso.HANDLER.post(new Runnable() {

            @Override public void run() {

              throw new AssertionError("Unhandled stats message." + msg.what);

            }

          });

      }

    }

就执行了performCacheHit方法,即cacheHits++

这里为什么绕了一个大弯子,picasso先是调用stats.dispatchCacheHit().该方法里通过handler发送一个消息,然后接收到消息后,把cacheHits++。为什么不直接在dispatchCacheHit方法里cacheHits++。比如像downloadCount,totalDownloadSize等成员变量就是直接++的。

build()里还有一行Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

Dispatcher是干什么的呢?这是一个分发器,所有的请求都在这里分发。

最后new Picasso对象返回。

--------------------------------with()到底结束--------------------

public RequestCreator load(Uri uri) {

    return new RequestCreator(this, uri, 0);

  }

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

    首先记录下开始时间,然后检查是不是主线程执行的。

    if (!data.hasImage())是什么意思呢?data是this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);

boolean hasImage() {

      return uri != null || resourceId != 0;

    }

所以这里是返回true的,所以暂时判断里的内容没有执行

if (deferred) {//deferred在这里是默认值false,所以花括号里的内容也没有执行

  Request request = createRequest(started);    //这里创建了请求,给请求唯一的id,url,并且可以转换request
  String requestKey = createKey(request);    //给请求创建了一个key
 if (shouldReadFromMemoryCache(memoryPolicy)) { 这里默认是进去的
     Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); 先根据requestKey到cache里找
    如果cache里能找到,就取消请求,直接设置
    if (callback != null) {
          callback.onSuccess();
     }    //如果我们之前传callback进来的话,在成功设置图片后,还可以回调这个方法
    如果cache里没有找到的话,

  if (setPlaceholder) {

      setPlaceholder(target, getPlaceholderDrawable());

    }//看有没有设置一个加载时默认显示的图片

    最重要的一行

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

    Action代表了一个具体的加载任务,里面有complete和error方法,主要用于回调

    U最后

picasso.enqueueAndSubmit(action);
     void enqueueAndSubmit(Action action) {

    Object target = action.getTarget();        //这个target就是ImageView

    if (target != null && targetToAction.get(target) != action) {    //如果这个image之前还没有请求过

      // This will also check we are on the main thread.

      cancelExistingRequest(target);

      targetToAction.put(target, action);

    }

    submit(action);

  }

    if里的,如果请求已经存在,则取消请求。重新放进去一遍

    最后提交

  void submit(Action action) {

    dispatcher.dispatchSubmit(action);

  }
   void dispatchSubmit(Action action) {

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

  }

   这时候这个Dispatcher就起到分发的作用。

  Dispatcher里的handleMessage方法里的

case REQUEST_SUBMIT: {

          Action action = (Action) msg.obj;

          dispatcher.performSubmit(action);

          break;

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

 注意这里的,hunter是一个Runnable,负责具体的加载,把最后加载的结果通过dispatcher分发出去

  if (result == null) {

        dispatcher.dispatchFailed(this);

      } else {

        dispatcher.dispatchComplete(this);

      }

这个是run方法里的一小段代码

picasso的源码分析(一)

标签:

原文地址:http://my.oschina.net/u/1777377/blog/413110

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!