美文网首页
Picasso 图片加载库源码分析5-流程中涉及的几个概念

Picasso 图片加载库源码分析5-流程中涉及的几个概念

作者: jkwen | 来源:发表于2021-07-04 07:31 被阅读0次

接下去计划将要从 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,到遇到异常就展示配置的或者指定的一张异常图片,表示出现异常了。

相关文章

网友评论

      本文标题:Picasso 图片加载库源码分析5-流程中涉及的几个概念

      本文链接:https://www.haomeiwen.com/subject/ewzuultx.html