Picasso代码初探

Picasso代码初探

简介

Picasso是square开源的一个Android网络图片处理的库,鉴于使用过okHttp、Retrofit等square的NB库,因此打算尝试下Picasso,了解下Picasso的NB之处。

使用

Picasso使用的语法与Glide一样,或者说Glide与Picasso一样...

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

代码的解读也主要基于上面这行代码。

代码查看

with方法

通过上述代码可以看出Picasso加载图片的代码使用构造器模式,通过链式传递Picasso单例。首先查看Picasso类中的with方法:

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

with方法为Picasso类的静态方法,通过构造器返回Picasso的全局单例。

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

通过build方法代码可以看出,Picasso实例包含许多内容,下载器、缓存、服务、请求发送等。下面一步一步的来看这几个实体:

  1. downloader
  2. cache
  3. service
  4. transformer

downloader

通过反射判断使用OkHttpLoaderCreator或者UrlConnectionDownloader,通过OkHttpLoaderCreator建立的downloader还会通过getCacheDir方法获取缓存路径建立文件名为“picasso-cache”的Picasso的缓存文件。其中OkHttpDownloader为通过OkHttp请求来下载网络图片的类,具体内容体现在后面讲述的load方法中。

cache

缓存默认使用LRU算法,即least-recently used,近期最少使用算法。首先在LruCache的构造函数中计算出一个合理的大小,作为缓存的最大空间。

static int calculateMemoryCacheSize(Context context) {
    ActivityManager am = getService(context, ACTIVITY_SERVICE);
    boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
    int memoryClass = am.getMemoryClass();
    if (largeHeap && SDK_INT >= HONEYCOMB) {
      memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
    }
    // Target ~15% of the available heap.
    return 1024 * 1024 * memoryClass / 7;
  }

使用可用内存堆的1/7作为图片缓存(不清楚这个大小有啥依据没有,本以为应该给更多空间)。关于具体内存大小,与Android系统配置相关,我参考的是这篇博客。

service

PicassoExecutorService实现Picasso线程池,构造函数中实例化工作队列和线程工厂。

transformer

RequestTransformer,请求在被执行前经过一层转换。

stat

通过Stat标记缓存的状态(命中数、未命中数、总大小、平均大小、下载次数等)

dispatcher

分发处理事件,如图片加载完成、请求提交、请求取消等。

load方法

通过传递的String返回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;
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
  }

Request同样使用Builder模式进行构建,设置基本参数。

into方法

public void into(Target target) {
    long started = System.nanoTime();
    checkMain();

    if (target == null) {
      throw new IllegalArgumentException("Target must not be null.");
    }
    if (deferred) {
      throw new IllegalStateException("Fit cannot be used with a Target.");
    }

    if (!data.hasImage()) {
      picasso.cancelRequest(target);
      target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
      return;
    }

    Request request = createRequest(started);
    String requestKey = createKey(request);

    if (shouldReadFromMemoryCache(memoryPolicy)) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        picasso.cancelRequest(target);
        target.onBitmapLoaded(bitmap, MEMORY);
        return;
      }
    }

    target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);

    Action action =
        new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
            requestKey, tag, errorResId);
    picasso.enqueueAndSubmit(action);
  }

into方法首先进行一系列的校验,如是否是在主(UI)线程,目标ImageView是否为空,URI或ResourceId是否为空等。经过校验后,建立请求,并通过请求生成一个requestKey,该Key即为缓存中缓存该图片的Key值,请求网络前先通过该Key检查图片是否在缓存中。否则将请求加入Picasso的请求队列中。

核心类为Dispatcher,通过DispatcherThread和BitmapHunter进行整个工作队列和Bitmap缓存等的管理。


Android开发新手,若有错误请指出,谢谢~

你可能感兴趣的:(Picasso代码初探)