Picasso--基本应用及源码浅析

Picasso是Squareup公司出的一款图片加载框架,能够解决我们在开发中加载图片时遇到的许多问题,其中最重要的是解决了加载大量图片时出现卡顿的问题,提高了加载速度,使图片能够平滑的加载。
1、基本应用

Picasso.with(this)
            //加载网络图片
            .load(url)
            //对图片进行剪裁,200表示200px
            .resize(200,200)
            //与resize一起使用,用于图片缩放
            .centerCrop()//完全填满ImageView,多余部分被裁掉(CenterInside使图片完全显示,但可能无法填满ImageView)
            //fit不可以和resize一起使用,缩小图片的尺寸去适配ImageView
            //.fit()
            //在transform方法中对图片进行二次处理
            .transform(transformation)
            //占位图,图片加载出来之前显示的默认图片  
            .placeholder(R.mipmap.ic_launcher)  
            //错误图,图片加载出错时显示的图片  
            .error(R.mipmap.ic_launcher) 
            //设置缓存策略 
            //第一个参数是指图片加载时放弃在内存缓存中查找  
            //第二个参数是指图片加载完不缓存在内存中  
            .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
            //在iv中show
            .into(iv);
            //在加载过程中设置监听器
           .into(iv, new Callback() {  
            @Override  
            public void onSuccess() { 
            }  
            @Override  
            public void onError() {  
            }  
        });
Transformation transformation = new Transformation() {  
            @Override  
            public Bitmap transform(Bitmap source) {  
                  //对图片进行二次处理
                }  
                return blankBitmap;  
            }  
        };  

2、源码浅析
先从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;  
}

这是一个单例,在创建Picasso的过程中,调用了new Builder(context).build()方法,说明Picasso实例创建的代码在build方法中,那就来看看这个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();  
  }  
  //Request转换器,用于在提交任务之前做一些处理,默认不做处理
  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);  
}

先看第一个条件判断

  if (downloader == null) {  
    downloader = Utils.createDefaultDownloader(context);  
  } 

如果使用with方法downloader肯定为null,则系统会创建一个默认的downloader

static Downloader createDefaultDownloader(Context context) {  
  try {  
    Class.forName("com.squareup.okhttp.OkHttpClient");  
    return OkHttpLoaderCreator.create(context);  
  } catch (ClassNotFoundException ignored) {  
  }  
  return new UrlConnectionDownloader(context);  
}

系统通过反射来检查项目中是否使用了OkHttp,如果使用了,就使用OkHttp来创建一个下载器,否则就使用HttpUrlConnection来创建,Class.forName("com.squareup.okhttp.OkHttpClient");这个方法的参数,这是OkHttp3以前的写法,现在使用的OkHttp3的包名就不是这个,而是okhttp3.OkHttpClient,所以如果项目中引用的是OkHttp3,Picasso还是会把HttpUrlConnection当作下载器来下载图片的。
第二个条件判断

  if (cache == null) {  
    cache = new LruCache(context);  
  }  

实例化LruCache,其内部使用的是LinkedHashMap

public LruCache(Context context) {
        this(Utils.calculateMemoryCacheSize(context));
    }

    public LruCache(int maxSize) {
        if(maxSize <= 0) {
            throw new IllegalArgumentException("Max size must be positive.");
        } else {
            this.maxSize = maxSize;
            //LinkedHashMap是HashMap的一个子类,
            //它保留插入的顺序,输出的顺序和输入时的相同
            this.map = new LinkedHashMap(0, 0.75F, true);
        }
    }

第三个条件判断

  if (service == null) {  
    service = new PicassoExecutorService();  
  }  
class PicassoExecutorService extends ThreadPoolExecutor {
    private static final int DEFAULT_THREAD_COUNT = 3;

    PicassoExecutorService() {
        super(3, 3, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue(), new PicassoThreadFactory());
    } 
  ....  
}

PicassoExecutorService继承自ThreadPoolExecutor线程池,线程池中的核心线程数为3,线程池的最大线程数也为3,说明线程池中没有非核心线程,线程队列使用了优先级队列PriorityBlockingQueue(使用方法:.priority(Picasso.Priority.HIGH/MEDIUM/LOW))

    public Future submit(Runnable task) {
        PicassoExecutorService.PicassoFutureTask ftask = new PicassoExecutorService.PicassoFutureTask((BitmapHunter)task);
        this.execute(ftask);
        return ftask;
    }

可以看到在submit时,new PicassoFutureTask

    private static final class PicassoFutureTask extends FutureTask implements Comparable {
        private final BitmapHunter hunter;

        public PicassoFutureTask(BitmapHunter hunter) {
            super(hunter, (Object)null);
            this.hunter = hunter;
        }

        public int compareTo(PicassoExecutorService.PicassoFutureTask other) {
            Priority p1 = this.hunter.getPriority();
            Priority p2 = other.hunter.getPriority();
            //高优先级的请求放到队列前面
            //同等级的请求按照顺序先后执行
            return p1 == p2?this.hunter.sequence - other.hunter.sequence:p2.ordinal() - p1.ordinal();
        }
    }

可以看到PicassoFutureTask是一个实现了Comparable接口的FutureTask
另外在PicassoExecutorService这个类中还有一个方法:void adjustThreadCount(NetworkInfo info),对移动网络做了处理,在做网络类型判断时可以参考

你可能感兴趣的:(Picasso--基本应用及源码浅析)