一、Picasso设置及使用:
在build.gradle中添加依赖:
compile 'com.squareup.picasso:picasso:2.5.2'
设置Picasso:
Picasso picasso = new Picasso.Builder(this)
.memoryCache(new LruCache()) // 设置自定义的内存缓存
.addRequestHandler(requestHandler) // 设置自定义的RequestHandler
.defaultBitmapConfig(bitmapConfig) // 设置自定义的Bitmap Config
.downloader(okHttpDownloader) // 设置自定义的Downloader
.executor(executorService) // 设置自定义的线程池
.requestTransformer(transformer) // 设置自定义的Transformor
.listener(listener) // 添加Listener进行监听
.loggingEnabled(true) // 设置日志打印
.build();
picasso.load(url)
.placeholder(defaultDrawable)
.error(errorDrawable)
.resize(width, height)
.centerInside()
.into(imageView);
二、源码分析
(一)Picasso中重要类介绍
1. Action:描述Picasso的每次请求行为所包含的数据,以及每次请求完成和错误的处理,此类是所有Action的基类,继承时需要实现以下两个函数:
abstract void complete(Bitmap result, Picasso.LoadedFrom from);
abstract void error();
主要成员变量:
final Picasso picasso;
final Request request;
final WeakReference<T> target; //外部传入的ImageView,
final boolean noFade; //是否渐变的出现
final int memoryPolicy; //内存策略
final int networkPolicy; //网络策略
final int errorResId; //错误时展示的图片id
final Drawable errorDrawable; //错误时展示的图片Drawable,和errorResId任给一个
final String key; //根据每一个Request生成一个唯一的key值,用于在内存中缓存每一个key对应的bitmap,比如两个Request的uri及其他参数都一样,这时候就会直接读取缓存的值
final Object tag; //用于暂停、重新运行或者取消某一个Request
boolean willReplay; //标识是否需要重新请求
boolean cancelled; //标识请求是否已取消
我们注意到在Action的构造函数中有这么一个赋值
this.target = target == null ? null : new RequestWeakReference<T>(this, target, picasso.referenceQueue);
static class RequestWeakReference<M> extends WeakReference<M> {
final Action action;
public RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
super(referent, q);
this.action = action;
}
}
这里用到了弱引用,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
下面介绍Action的子类:
(1)FetchAction:获取图片,并在成功或者失败后回调onSuccess或者onError给调用者。一般用于提前缓存图片
(2)GetAction:成功失败都没有回调,因为他是用在同步获取图片时使用,使用时不能放在主线程
(3)TargetAction:将获取的图片放到target里面,使用时需要先实现Taget接口,这有助于自己对图片进行灵活的处理,比如保存等
public interface Target {
void onBitmapLoaded(Bitmap bitmap, LoadedFrom from);
void onBitmapFailed(Drawable errorDrawable);
void onPrepareLoad(Drawable placeHolderDrawable);
}
(4)NotificationAction:名字已经告诉我们这个图片是用于通知类消息中,在图片加载完成时会notify通知状态栏
(5)AppWidgetAction:用于widget的图片加载,图片加载完成时会自动调用更新widget的方法
(6)ImageViewAction:这个是最常用的Action,图片加载完成时会直接显示到ImageView
2. RequestHandler:请求处理的基类,对应不同请求都需要实现以下两个虚函数
public abstract boolean canHandleRequest(Request data); //判断是否能处理
public abstract Result load(Request request, int networkPolicy) throws IOException; //实际的网络请求或者图片资源加载
它里面还有一个对处理结果描述的静态内部类Result
public static final class Result {
private final Picasso.LoadedFrom loadedFrom; //MEMORY(Color.GREEN), DISK(Color.BLUE), NETWORK(Color.RED);
private final Bitmap bitmap;
private final InputStream stream;
private final int exifOrientation; //可交换图像文件的初始方向,比如0 90 180 270度
}
RequestHandler的子类:
(1)AssetRequestHandler:加载Asset中的图片资源,uri:file:///android_asset/xxx.png
(2)ResourceRequestHandler:加载资源文件中的图片,uri:R.drawable.xxx.png
(3)ContactsPhotoRequestHandler:联系人照片的图片加载,会先进行查询
(4)MediaStoreRequestHandler:媒体资源库图片加载
(5)ContentStreamRequestHandler:Provider图片
(6)FileRequestHandler:手机SD卡上面的图片加载
(7)NetworkRequestHandler:网络请求加载图片,这是最重要的一种方式
在Picasso的构造函数中会加入上面这个处理方法到数组中,调用的采用了责任链模式获取匹配的RequestHandler
for (int i = 0, count = requestHandlers.size(); i < count; i++) {
RequestHandler requestHandler = requestHandlers.get(i);
if (requestHandler.canHandleRequest(request)) {
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
3. BitmapHunter implements Runnable:很明显,这是一个运行在某个线程中的获取图片的类,在他的run方法中会去下载图片并处理各种异常,包括异常重试。实际的获取工作是在RequestHandler类中获取的,对获取的bitmap进行数据解析和各种Transforms,包括用户自定义的
4. Picasso:这个类主要是利用建造者模式对Picasso相关参数进行设置,以及创建主线程的Handler对成功获取的图片进行ImageView的设置
5. Dispatcher:主要进行任务的分发,在这个类里面专门建立了一个HandlerThread线程来处理各种请求,比如把请求提交到线程池执行。
6. LruCache:采用最近最少使用是缓存的策略,正好利用了LinkedHashMap的特点
7. OkHttpDownloader:具体执行下载工作的类,load函数中设置了网络请求策略并采用OkHttp来获取图片
8. PicassoExecutorService:自定义线程池类,根据,可以在网络变化时动态调整核心线程池的数目,返回可以查询结果的FutureTask
9. RequestCreator:根据参数创建Picasso请求的类,主要是对图片的各种属性设置,比如大小,旋转,自定义变换等
10. UrlConnectionDownloader:对于没有okhttp的情况,采用原始的HttpURLConnection方式来下载图片
11. Stats:统计类,对下载图片的总大小、下载次数、变换次数等等进行统计,也是用了一个HandlerThread来专门负责
主要的类就介绍到这里,Picasso中的数据关联关系相对复杂,因此在进行下面的流程分析之前,先给一个数据关系结构图:
图一 Picasso数据结构图
(二)Picasso函数调用流程分析
先从Picasso的初始化说起:我们可以使用Picasso默认的构造,这里使用了门面模式和单例模式方便我们使用
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
当然我们也可以自定义,这里使用了建造者模式来构建Picasso
Picasso picasso = new Picasso.Builder(this)
.memoryCache(new LruCache()) // 设置自定义的内存缓存
.addRequestHandler(requestHandler) // 设置自定义的RequestHandler
.defaultBitmapConfig(bitmapConfig) // 设置自定义的Bitmap Config
.downloader(okHttpDownloader) // 设置自定义的Downloader
.executor(executorService) // 设置自定义的线程池
.requestTransformer(transformer) // 设置自定义的requestTransformer
.listener(listener) // 添加Listener进行监听
.loggingEnabled(true) // 设置日志打印
.build();
我们来看看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);
}
这里我们需要来看下Utils.createDefaultDownloader
static Downloader createDefaultDownloader(Context context) {
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException ignored) {
}
return new UrlConnectionDownloader(context);
}
这里会反射判断是否包含okhttp.OkHttpClient这个类,如果没有就会使用HttpURLConnection来下载。但是我们如果使用okhttp3的话肯定会返回HttpURLConnection,这时候如果想用okhttp3就需要自定义Downloader了。创建好了Picasso,我们来看下怎么使用的:
picasso.load(url)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.networkPolicy(NetworkPolicy.NO_CACHE)
.transform(new Transformation() //对获取的bitmap进行自定义变换
.placeholder(defaultDrawable)
.error(errorDrawable)
.resize(width, height)
.centerInside()
.into(imageView);
public RequestCreator load(Uri uri)
public RequestCreator load(String path)
public RequestCreator load(File file)
public RequestCreator load(int resourceId)
Picasso提供了4个load函数,分别加载不同的图片资源,第2,3两个函数都会转换调用第一个,注意到他们都返回了一个RequestCreator变量,load后面的函数都是RequestCreator提供的,它提供了对图片的各种设置,比如大小、旋转、自定义变换等,而实际开始处理图片的是into方法。
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.");
}
//判断是否设置了url或者resourceId,如果都没设置就取消请求并返回
if (!data.hasImage()) {
picasso.cancelRequest(target); //取消并释放资源
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable()); //设置前面传的错误占位图片
}
return;
}
//如果设置了.fit()方法deferred会置为true进入if判断
if (deferred) {
if (data.hasSize()) { //如果有预先设置值会报错,因为fit方法会适应传入的ImageView的大小
throw new IllegalStateException("Fit cannot be used with resize.");
}
int width = target.getWidth();
int height = target.getHeight();
if (width == 0 || height == 0) { //为0说明ImageView还未渲染完成
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
//这里DeferredRequestCreator implements ViewTreeObserver.OnPreDrawListener,当ImageView绘制之前会回调onPreDraw()函数,这个时候已经测量完了宽高的值,在onPreDraw()函数中会再次调用into函数,并把deferred置为false
picasso.defer(target, new DeferredRequestCreator(this, target, callback));
return;
}
data.resize(width, height);
}
//根据之前传入的图片uri, resourceId,大小,旋转角度等来build一个Request,并调用requestTransformer返回新的Request
Request request = createRequest(started);
//根据Request里面的参数来创建一个字符串的可以,用于对已经获取的bitmap进行缓存
String requestKey = createKey(request);
if (shouldReadFromMemoryCache(memoryPolicy)) { //根据设置的策略来判断是否读取缓存
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); //直接读取缓存中的bitmap
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); //创建一个action并提交
}
这里引用一张流程图(https://blog.youkuaiyun.com/woliuyunyicai/article/details/51417839)
图二 into函数流程图
Picasso#enqueueAndSubmit->submit->dispatchSubmit
void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
//更新存储的target对应的action,取消旧的
if (target != null && targetToAction.get(target) != action) {
// This will also check we are on the main thread.
cancelExistingRequest(target);
targetToAction.put(target, action);
}
submit(action);
}
void submit(Action action) { //RequestCreator.java
dispatcher.dispatchSubmit(action); //利用dispatcher中的新线程专门处理分发任务
}
void dispatchSubmit(Action action) { //Dispatcher.java
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action)); //主线程向dispatcher线程发送任务
}
senMessage就从主线程切换到了dispatcher线程,下面来看下它处理了哪些message
Dispatcher#DispatcherHandler
private static class DispatcherHandler extends Handler { //Dispatcher.java
private final Dispatcher dispatcher;
public DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override public void handleMessage(final Message msg) {
switch (msg.what) {
case REQUEST_SUBMIT: { //执行提交到线程池的操作
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
case REQUEST_CANCEL: { //取消请求
Action action = (Action) msg.obj;
dispatcher.performCancel(action);
break;
}
case TAG_PAUSE: { //根据tag来暂停
Object tag = msg.obj;
dispatcher.performPauseTag(tag);
break;
}
case TAG_RESUME: {
Object tag = msg.obj;
dispatcher.performResumeTag(tag);
break;
}
case HUNTER_COMPLETE: { //bitmap获取完成
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
case HUNTER_RETRY: { //失败重试
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
case HUNTER_DECODE_FAILED: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performError(hunter, false);
break;
}
case HUNTER_DELAY_NEXT_BATCH: { //批处理
dispatcher.performBatchComplete();
break;
}
case NETWORK_STATE_CHANGE: { //当网络状态变化时更新核心线程数。比如WIFI状态的核心线程就为4个,而4G,3G,2G状态下的线程数分别为3,2,1个;
NetworkInfo info = (NetworkInfo) msg.obj;
dispatcher.performNetworkStateChange(info);
break;
}
case AIRPLANE_MODE_CHANGE: {
dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
break;
}
default:
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new AssertionError("Unknown handler message received: " + msg.what);
}
});
}
}
}
初始化函数中的looper是从HandlerThread中获取的,下面的handleMessage是运行在另外一个非主线程中的
REQUEST_SUBMIT把任务直接交给了dispatcher类来处理
Dispatcher#performSubmit
void performSubmit(Action action, boolean dismissFailed) { //Dispatcher.java
if (pausedTags.contains(action.getTag())) { //如果tag已经标记为暂停,则直接返回了
pausedActions.put(action.getTarget(), action);
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
"because tag '" + action.getTag() + "' is paused");
}
return;
}
//如果已经缓存过某个任务,则合并action。比如对同一个url的图片任务(图片的大小,旋转等参数也要一致),在两个不同的地方使用,第二次就会调用attach合并action。当bitmap请求回来之后会根据attach的action给不同的imageview赋值
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;
}
//这里前面已经提到过,根据不同的加载任务,采用责任链模式来获取对应的RequestHandler,再构造一个BitmapHunter返回
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
hunter.future = service.submit(hunter); //提交到线程池处理
hunterMap.put(action.getKey(), hunter); //缓存key对应的任务
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
submit提交到线程池后,线程池就会取出任务放在线程中执行,BitmapHunter是实现了runnable接口的,所以这时候就会跳转到BitmapHunter#run方法执行
BitmapHunter#run
@Override public void run() {
try {
updateThreadName(data); //更新线程名字
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
}
result = hunt(); //这里是重点,会实际去获取bitmap并根据大小,选择,变换等进行处理后返回
//再次切换到dispatcher线程去执行
if (result == null) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
} catch (Downloader.ResponseException e) {
if (!e.localCacheOnly || e.responseCode != 504) {
exception = e;
}
dispatcher.dispatchFailed(this);
} catch (NetworkRequestHandler.ContentLengthException e) {
exception = e;
dispatcher.dispatchRetry(this); //出错重试,再次切换到dispatcher线程去重新发送请求
} catch (IOException e) {
exception = e;
dispatcher.dispatchRetry(this); //出错重试,再次切换到dispatcher线程去重新发送请求
} catch (OutOfMemoryError e) {
StringWriter writer = new StringWriter();
stats.createSnapshot().dump(new PrintWriter(writer));
exception = new RuntimeException(writer.toString(), e);
dispatcher.dispatchFailed(this);
} catch (Exception e) {
exception = e;
dispatcher.dispatchFailed(this);
} finally {
Thread.currentThread().setName(Utils.THREAD_IDLE_NAME); //更改线程名称
}
}
我们来看看重试的机制
Dispatcher#performRetry
void performRetry(BitmapHunter hunter) {
if (hunter.isCancelled()) return;
if (service.isShutdown()) { //服务已关闭
performError(hunter, false); //移除缓存中当前的hunter,批处理其它的hunter
return;
}
NetworkInfo networkInfo = null;
if (scansNetworkChanges) { // 用户是否允许联网
ConnectivityManager connectivityManager = getService(context, CONNECTIVITY_SERVICE);
networkInfo = connectivityManager.getActiveNetworkInfo();
}
boolean hasConnectivity = networkInfo != null && networkInfo.isConnected(); //判断是否联网
//默认两次重试机会,如果重试次数大于0且已联网则返回true
boolean shouldRetryHunter = hunter.shouldRetry(airplaneMode, networkInfo);
boolean supportsReplay = hunter.supportsReplay(); //默认返回的true
if (!shouldRetryHunter) {
// Mark for replay only if we observe network info changes and support replay.
boolean willReplay = scansNetworkChanges && supportsReplay;
performError(hunter, willReplay);
if (willReplay) {
markForReplay(hunter); //标记重试
}
return;
}
// If we don't scan for network changes (missing permission) or if we have connectivity, retry.
if (!scansNetworkChanges || hasConnectivity) {
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_RETRYING, getLogIdsForHunter(hunter));
}
//noinspection ThrowableResultOfMethodCallIgnored
if (hunter.getException() instanceof NetworkRequestHandler.ContentLengthException) {
hunter.networkPolicy |= NetworkPolicy.NO_CACHE.index; //如果读取内容长度异常,则不再使用缓存
}
hunter.future = service.submit(hunter); //重新提交到线程池
return;
}
performError(hunter, supportsReplay);
if (supportsReplay) {
markForReplay(hunter);
}
}
再来看一下获取图片的实际请求类,在这里会调用okhttp执行网络请求
Dispatcher#hunt
Bitmap hunt() throws IOException {
Bitmap bitmap = null;
if (shouldReadFromMemoryCache(memoryPolicy)) { //如果缓存有则直接返回
bitmap = cache.get(key);
if (bitmap != null) {
stats.dispatchCacheHit();
loadedFrom = MEMORY;
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
}
return bitmap;
}
}
data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
//这里会调用requestHandler中的load去获取图片,对应不同的资源,实际执行的load方法也不相同。例如对于网络请求会调用NetworkRequestHandler#load方法,这个方法会再去调用传入的OkHttpDownloader中的load方法,此方法会根据不同的网络策略,直接利用okhttp去请求数据
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
if (result != null) {
loadedFrom = result.getLoadedFrom();
exifRotation = result.getExifOrientation();
bitmap = result.getBitmap();
// If there was no Bitmap then we need to decode it from the stream.
if (bitmap == null) {
InputStream is = result.getStream();
try {
//根据用户设定的宽和高来计算options.inSampleSize,再根据这个把数据流解析成bitmap
bitmap = decodeStream(is, data);
} finally {
Utils.closeQuietly(is);
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
stats.dispatchBitmapDecoded(bitmap); //更新统计
if (data.needsTransformation() || exifRotation != 0) {
//锁定一个空对象,保证同一个时间自由一个线程在处理各种变换,以避免OOM,作者说是从Volley学过来的
synchronized (DECODE_LOCK) {
if (data.needsMatrixTransform() || exifRotation != 0) {
//进行大小,旋转,centerCrop,centerCrop等操作
bitmap = transformResult(data, bitmap, exifRotation);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
}
}
//如果用户设置了自定义的变换,则回调用户已经设置好的变换方法
if (data.hasCustomTransformations()) {
bitmap = applyCustomTransformations(data.transformations, bitmap);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
}
}
}
if (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}
到这里,经过网络请求,各种变换后的bitmap总算得到了,但是现在在线程池分配的线程里,我们马上调用Dispatcher的方法切换到dispatcher线程进行后续的bitmap处理
Dispatcher#performComplete->batch->performBatchComplete
void performComplete(BitmapHunter hunter) {
if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
cache.set(hunter.getKey(), hunter.getResult());判断是否写入缓存
}
hunterMap.remove(hunter.getKey());
batch(hunter); //加入批处理列表
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
}
}
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); //delay200ms,在此期间的都会合并处理
}
}
void performBatchComplete() {
List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch); //深拷贝一份
batch.clear();
//发送给Picasso中的Handler处理,因为需要在主线程更新UI
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}
最后把要处理的列表传给了主线程的Handler,那么我们继续跟进
Picasso#HANDLER
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case HUNTER_BATCH_COMPLETE: {
@SuppressWarnings("unchecked") List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = batch.size(); i < n; i++) {
BitmapHunter hunter = batch.get(i);
hunter.picasso.complete(hunter); //循环处理所有的hunter
}
break;
}
case REQUEST_GCED: {
Action action = (Action) msg.obj;
if (action.getPicasso().loggingEnabled) {
log(OWNER_MAIN, VERB_CANCELED, action.request.logId(), "target got garbage collected");
}
action.picasso.cancelExistingRequest(action.getTarget());
break;
}
case REQUEST_BATCH_RESUME:
@SuppressWarnings("unchecked") List<Action> batch = (List<Action>) msg.obj;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = batch.size(); i < n; i++) {
Action action = batch.get(i);
action.picasso.resumeAction(action);
}
break;
default:
throw new AssertionError("Unknown handler message received: " + msg.what);
}
}
};
注意到这里的Looper传入的是MainLooper,也就是说handleMessage是在主线程运行的,所以可以更新UI。如果new Handler()时不传入Looper,那么会使用创建时线程的Looper,换句话说那就是在哪个线程创建就运行在哪个线程。
Picasso#complete
void complete(BitmapHunter hunter) {
Action single = hunter.getAction();
List<Action> joined = hunter.getActions();
boolean hasMultiple = joined != null && !joined.isEmpty();
boolean shouldDeliver = single != null || hasMultiple;
if (!shouldDeliver) { //没有需要处理的数据就返回
return;
}
Uri uri = hunter.getData().uri;
Exception exception = hunter.getException();
Bitmap result = hunter.getResult(); //获取在BitmapHunter中获取的bitmap
LoadedFrom from = hunter.getLoadedFrom();
if (single != null) {
deliverAction(result, from, single); //处理当前的actin
}
//如果之前调用过Attach方法,这时候还会有其他的action
if (hasMultiple) {
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = joined.size(); i < n; i++) {
Action join = joined.get(i);
deliverAction(result, from, join);
}
}
if (listener != null && exception != null) {
listener.onImageLoadFailed(this, uri, exception); //异常回调
}
}
Picasso#deliverAction
private void deliverAction(Bitmap result, LoadedFrom from, Action action) {
if (action.isCancelled()) {
return;
}
if (!action.willReplay()) {
targetToAction.remove(action.getTarget());
}
if (result != null) {
if (from == null) {
throw new AssertionError("LoadedFrom cannot be null.");
}
action.complete(result, from); //调用action的complete方法处理bitmap,具体怎么处理要看action的实现类
if (loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
}
} else {
action.error();
if (loggingEnabled) {
log(OWNER_MAIN, VERB_ERRORED, action.request.logId());
}
}
}
ImageViewAction#complete
@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
if (result == null) {
throw new AssertionError(
String.format("Attempted to complete action with no result!\n%s", this));
}
ImageView target = this.target.get();
if (target == null) {
return;
}
Context context = picasso.context;
boolean indicatorsEnabled = picasso.indicatorsEnabled;
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled); //接着又调了静态函数setBitmap
if (callback != null) {
callback.onSuccess(); //如果设置了回调函数则回调
}
}
PicassoDrawable#setBitmap
static void setBitmap(ImageView target, Context context, Bitmap bitmap,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
Drawable placeholder = target.getDrawable();
if (placeholder instanceof AnimationDrawable) {
((AnimationDrawable) placeholder).stop();
}
PicassoDrawable drawable =
new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
target.setImageDrawable(drawable); //这里用到了我们常用的方法
}
引用一张图来描述请求流程: