接下去计划将要从 RequestCreator 的 into 方法开始流程分析,这过程会涉及到前面梳理的几个点,以及数据传递,目标是分析出最终图片的展示。
不过在流程分析前,还需要提前分析几个类,了解一下大致意思,避免在流程分析时遇到他们而出现卡壳,那样对我们流程宏观和细节理解都不好。
Stats
Stats(Cache cache) {
this.cache = cache;
//HandlerThread,本质上是 Thread,但它支持消息通信,有自己的 Looper
this.statsThread = new HandlerThread(STATS_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
this.statsThread.start();
Utils.flushStackLocalLeaks(statsThread.getLooper());
//对应前面子线程的 Handler 对象,用于消息发送,处理
this.handler = new StatsHandler(statsThread.getLooper(), this);
}
从构造方法上看,这个类提供了一个可以用来消息更新的线程,线程的优先级同线程池里的一样。它的作用,我猜测可能是和内存缓存的状态有关。
@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;
}
}
Picasso 构造方法
{
int builtInHandlers = 7;
int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
allRequestHandlers.add(new ResourceRequestHandler(context));
if (extraRequestHandlers != null) {
allRequestHandlers.addAll(extraRequestHandlers);
}
allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
allRequestHandlers.add(new MediaStoreRequestHandler(context));
allRequestHandlers.add(new ContentStreamRequestHandler(context));
allRequestHandlers.add(new AssetRequestHandler(context));
allRequestHandlers.add(new FileRequestHandler(context));
allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));
requestHandlers = Collections.unmodifiableList(allRequestHandlers);
}
构造方法里有一个需要值得关注的概念是 RequestHandler,意为对图片加载请求的处理。Picasso 内置了 7 种处理方式,对应着图片资源表示的常规方式,例如 Resource 资源,File 文件,网络图片等。我们也可以通过继承 RequestHandler 抽象类来实现自定义的处理,以网络加载请求为例看下 NetworkRequestHandler 的工作,
@Override public boolean canHandleRequest(Request data) {
String scheme = data.uri.getScheme();
//这里要求满足 http 或 https 为开头的请求连接
return (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme));
}
@Override public Result load(Request request, int networkPolicy) throws IOException {
okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
//发起 okhttp 请求,这个 downloader 就是之前说过的 OkHttp3Downloader 对象
Response response = downloader.load(downloaderRequest);
ResponseBody body = response.body();
Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;
if (loadedFrom == DISK && body.contentLength() == 0) {
body.close();
throw new ContentLengthException("Received response with 0 content-length header.");
}
if (loadedFrom == NETWORK && body.contentLength() > 0) {
//从网络中获取,会调用 Stats 对象的方法
//这个方法其实就是发送了一个 DOWNLOAD_FINISHED 消息,统计了下载量
stats.dispatchDownloadFinished(body.contentLength());
}
//返回结果,此时还不是 Bitmap 格式
return new Result(body.source(), loadedFrom);
}
重点是对 RequestHandler 里 canHandleRequest 和 load 抽象方法的实现,canHandlerRequest 用来判断能否处理这个请求,load 用来具体处理请求。
ImageViewAction
在调用 RequestCreator 的 into 方法最后,会创建 ImageViewAction 对象,用来表示这次图片加载请求。它继承自泛型抽象类 Action<T>,里面成员变量还挺多,我们就关注抽象方法 complete 和 error 就好。
@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
ImageView target = this.target.get();
if (target == null) {
return;
}
//看样子就是图片最后的展示了,注意涉及到 UI 的要保证在主线程
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
//这里还可以监听回调
if (callback != null) {
callback.onSuccess();
}
}
@Override public void error(Exception e) {
ImageView target = this.target.get();
if (target == null) {
return;
}
//这么看来,这个 error 并不是表示报错,而是展示错误结果的图片
if (errorResId != 0) {
target.setImageResource(errorResId);
} else if(errorDrawable != null) {
target.setImageDrawable(errorDrawable);
}
if (callback != null) {
callback.onError(e);
}
}
对比两个方法,其实都是做一件事情(展示图片),无非是正常情况下走 complete,到遇到异常就展示配置的或者指定的一张异常图片,表示出现异常了。
网友评论