美文网首页
Picasso 图片加载库源码分析1-从使用方法着手

Picasso 图片加载库源码分析1-从使用方法着手

作者: jkwen | 来源:发表于2021-06-30 22:59 被阅读0次

如果想用 Picasso 展示一张图片,可以这样调用,只要一行代码就能展示图片了,图片的来源可以是本地,资源文件或者网络。

Picasso.get().load(res).into(imageview)

我们就以此作为切入点分析一下其源码实现逻辑。

get 方法

public static Picasso get() {
    if (singleton == null) {
        synchronized (Picasso.class) {
            if (singleton == null) {
                if (PicassoProvider.context == null) {
                    throw new IllegalStateException("context == null");
                }
                singleton = new Builder(PicassoProvider.context).build();
            }
        }
    }
    return singleton;
}

get 方法实际上是单例模式的表现,采用 DCL 的写法实现单例。PicassoProvider 继承自 ContentProvider,不太明白这样获取 Context 对象的用意,这里就认为它提供了上下文。接下去采用了 Builder 模式,在 Picasso 类里有个静态类 Builder,通过它来创建了 Picasso 对象。

有这么几个东西是可配的,也是后面梳理的重点。这就有点像 Retrofit 对象的创建。

  • Downloader 定义了从外部加载图片的方式(是磁盘还是网络),它是一个接口,提供了 load 和 shutdown 方法。默认的实现类是 OkHttp3Downloader。
  • Cache 定义了内存缓存的方式,就整个库来看默认是以最近最少使用算法为实现原理,它是一个接口,提供了 get, set, size, maxSize, clear, clearKeyUri 这些方法。默认的实现类是 LruCache。
  • PicassoExecutorService 定义了线程池,继承自 ThreadPoolExecutor,具体这个线程池用来做什么目前还不清楚,先知道有这么个东西。
  • RequestTransformer 应该是定义了图片加载请求变换的方式,它是一个接口,提供了 transformRequest 方法。默认是不做任何变换的,具体实现类应该很多,这个留到后面分析。
  • Stats 创建时需要传入内存缓存方式,目前还不知道是什么作用。

由上述几个属性会创建一个 Dispatcher 对象,

Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

这里还没了解其作用,就拿 OkHttp 对比来说,有可能的作用是负责图片加载请求任务的管理。其中 HANDLER 入参是 Picasso 类里的一个静态 Handler 类,且消息处理是在 Android 主线程。

最后再结合其他一些属性变量创建了 Picasso 对象并返回。

load 方法

public RequestCreator load(@Nullable Uri uri) {
    return new RequestCreator(this, uri, 0);
}

load 方法其实有多种重载,但最终的工作就是创建了一个 RequestCreator 对象,这个 RequestCreator 从名字上看是个请求创建者,这个请求当然就是指图片加载请求,类注释上说可以流畅的创建图片加载请求,来稍微看下流畅怎么体验,学学人家的写法。

RequestCreator(Picasso picasso, Uri uri, int resourceId) {
    this.picasso = picasso;
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}

这个 data 是 Request 类里面的静态类 Builder,看来还是用了 Builder 模式。光这步可能还不能体现流畅(我估计流畅主要还是指 Builder 模式的运用),先继续往下看。

into 方法

这个方法异步形式将图片加载请求结果展示在控件上,这个控件指定为 ImageView。有一点要注意,为了防止内存泄漏,对 ImageView 对象的引用是弱引用,从而保证 ImageView 对象能够及时被回收避免内存泄漏的情况(这点也是我们在做和页面相关的引用关联时要特别注意的)。

public void into(ImageView target) {
    into(target, null);
}
public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    checkMain();
    //上面这两句贴出来是想学习下他的写法,
    //一个是用来获取 nano 时间,这个时间精度更高,近似 cpu 的时间片精度吧
    //一个是用来判断当前线程是否为主线程
    
    //hasImage 用来判断调用 into 方法的时候有没有传入有效的图片资源 Uri
    //如果没有,显然就会终止
    if (!data.hasImage()) {
        picasso.cancelRequest(target);
        //省略部分代码....
        return;
    }
    //deferred 感觉是个是否调整尺寸或者适配的控制
    //默认应该是 false,如果需要调整,其实也是对尺寸属性的一个赋值
    if (deferred) {
        int width = target.getWidth();
        int height = target.getHeight();
        if (width == 0 || height == 0) {
            return;
        }
        data.resize(width, height);
    }
    //这句比较核心,本质上就是通过 data 变量去 build 出一个 Request 对象
    //Request 对象其实是个数据对象,里面存储这图片信息以及变换,展示尺寸等信息
    Request request = createRequest(started);
    //这个 key 就是用来缓存用的,key 的生成也可以借鉴一下,省的自己只会 UUID.random 的写法
    String requestKey = createKey(request);
    //这句判断是否先从缓存中读取,如果有就加载展示图片
    if (shouldReadFromMemoryCache(memoryPolicy)) {
        //通过 picasso 对象,利用前面说的图片 key 去查找图片
        Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
        if (bitmap != null) {
            //如果图片找到了,就取消当前的请求,就用找到的这张图片
            //所以这里有个细节,就是如果图片的 key 没有变,那么即使图片内容再怎么变,
            //图片最终的展示也不会变,所以图片展示要刷新,就要更新 key
            picasso.cancelRequest(target);
            //设置图片展示,内部本质是调用 ImageView 的 setImageDrawable 方法
            setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
            //最后如果想监听回调,可以在这里接收到
            if (callback != null) {
                callback.onSuccess();
            }
            return;
        }
    }
    //如果缓存里没有图片,就会创建一个 Action 对象发起请求处理吧
    Action action = new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId, errorDrawable, requestKey, tag, callback, noFade);
    picasso.enqueueAndSubmit(action);
}

看来前面说 RequestCreator 流畅还是指的 Builder 模式运用,再往里深入就和 RequestCreator 没太大关系了。后面再展开分析内部的各个奥妙点。

相关文章

网友评论

      本文标题:Picasso 图片加载库源码分析1-从使用方法着手

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