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方法里的一小段代码