一、例子
如下就是Picasso最简单的例子,我们在使用的时候就是这么简单,直接with、load、into
// 普通加载图片
Picasso.with(PicassoActivity.this)
.load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")
.into(ivPicassoResult1);
// 裁剪的方式加载图片
Picasso.with(PicassoActivity.this)
.load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")
.resize(100,100)
.into(ivPicassoResult2);
// 选择180度
Picasso.with(PicassoActivity.this)
.load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg")
.rotate(180)
.into(ivPicassoResult3);
首先来看三个函数,第一个是with函数,很显然使用的是单例模式和Builder模式,然后创建一个Picasso的实例
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
public RequestCreator load(Uri uri) {
...
}
public RequestCreator load(String path) {
...
}
public RequestCreator load(int resourceId) {
...
}
最后是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);
}
这里最主要的就是创建一个Reques对象,我们前面做的一些封装和设置都会封装到这个Request对象中
检查我们要显示的图片是否可以直接在缓存中获取,如果有就直接显示出来好了。
缓存没命中,那就只能费点事把源图片down下来了。这个过程是异步的,并且通过一个Action来完成请求前后的衔接工作。
首先进行参数的设置,然后创建request请求对象,最后通过通过action来进行图片的请求。
1. 首先看一下构造函数
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
...
}
我们是通过单例和建造者模式来完成实例化的,在build的过程中向picasso中传递这些参数,自己来灵活的定制
2、看一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);
}
Cache:Picasso的缓存,这里实例化的是LruCache,其内部使用的是LinkedHashMap
ExecutorService:这里Picasso实现了自己的PicassoExecutorService,它继承了ThreadPoolExecutor,也就是Picasso自己维护了一个线程池,用于异步加载图片。
Stats:这个类只要是维护图片的一些状态Dispatcher:从名字上就可以判断出来,这个类在这里起到了一个调度器的作用,图片要不要开始下载以及下载后Bitmap的返回都是通过这个调度器来执行的
3、也是通过异步请求的方式来进行的
上面的into方法中中最终会创建一个action,这个action里边包含picasso对象、目标和Request请求等
然后会调用enqueueAndSubmit方法,而最终是调用了Dispatcher的dispatchSubmit方法,也就是我们前面说的,Dispatcher起到了调度器的作用。在Dispatcher内部,Dispatcher定义了DispatcherThread和DispatcherHandler两个内部类,并在Dispatcher的构造函数中对他们经行了实例化,所有的调度也都是通过handler异步的执行的,如下是Dispatcher
Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
Downloader downloader, Cache cache, Stats stats) {
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start();
...
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
...
}
构建实例之后建立一个
BitmapHunter类来进行图片的加载,这个类也是继承Runnable接口的类,加载完成图片之后怎么去进行进行主线程的更新是个问题
4、进行图片的主线程跟新操作
因为是异步的,最终也是通过消息机制来进行发送的,同message的方式发送到主线程中进行图片的渲染和更新的操作
Picasso并不是立即将图片显示出来,而是用到了一个批处理,其实就是把操作先暂存在一个list中,等空闲的时候再拿出来处理,这样做得好处也是尽量减少主线程的执行时间,一方面防止ANR,另一方面快速返回,响应页面的其他渲染操作,防止卡顿用户界面。
private void batch(BitmapHunter hunter) {
if (hunter.isCancelled()) {
return;
}
batch.add(hunter);
if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
}
}
尊重作者,尊重原创,参考文章:
http://www.jianshu.com/p/459c8ca3f337