美文网首页
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