Picasso-源码解析(二)

作者: javalong | 来源:发表于2018-12-06 22:34 被阅读2次

    前言

    前面一篇文章简单的介绍了Picasso的使用,已经整个源码调用的流程,过了一遍。但是其中还有很多的细节我们并没有去涉及到。今天在昨天的基础之上再进行深入。

    Picasso对象

    前面一篇文章我们是从Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(ivTest)慢慢深入的,这里我们也要找个可以深入的对象,就是最重要的Picasso对象。

    因为我们在使用的时候就是直接Picasso.get().***这样去调用的,所以说我们先了解下Picasso所有的api,对整个框架的理解,以及对Picasso更有效率的使用。

    public方法

    image.png

    我们的as很强大,直接左侧栏查看当前类的公用方法.

    这里就把方法一个个介绍下。便于大家理解。

    1. areIndicatorsEnabled(),setIndicatorsEnabled()
      @SuppressWarnings("UnusedDeclaration") public void setIndicatorsEnabled(boolean enabled) {
        indicatorsEnabled = enabled;
      }
      @SuppressWarnings("UnusedDeclaration") public boolean areIndicatorsEnabled() {
        return indicatorsEnabled;
      }
    

    用来设置和获取是否显示当前加载图片的方式,上一篇文章有使用过,就是显示当前图片是由三级缓存中的哪一个加载的。

    1. cancelRequest
      看名字就知道,是直接用来取消请求的。
      这里可以深入下。
     public void cancelRequest(@NonNull ImageView view) {
        if (view == null) {
          throw new IllegalArgumentException("view cannot be null.");
        }
        cancelExistingRequest(view);
      }
    void cancelExistingRequest(Object target) {
        checkMain();
        //前面在加载图片的时候是会target-action以key-value的方式保存在targetToAction中,后面我会指出,在哪里保存的。这里直接通过target获取到action,然后cancel
        Action action = targetToAction.remove(target);
        if (action != null) {
          action.cancel();
          dispatcher.dispatchCancel(action);
        }
        //这里就比较有意思,因为第一篇文章我们介绍过,如果是`ImageView`的话,很可能会使用fit方法去适配`ImageView`的宽高,就有使用到DeferredRequestCreator,所以这里要移除
        if (target instanceof ImageView) {
          ImageView targetImageView = (ImageView) target;
          DeferredRequestCreator deferredRequestCreator =
              targetToDeferredRequestCreator.remove(targetImageView);
          if (deferredRequestCreator != null) {
            deferredRequestCreator.cancel();
          }
        }
      }
    
    
    1. cancelTag,pauseTag,resumeTag
      这3个一起说,这3个可以说是批量操作符。可以简单的看一下。
    Picasso.get().load("http://i.imgur.com/DvpvklR.png")
                    .tag("test")
                    .into(ivTest)
            Picasso.get()
                    .load("http://i.imgur.com/DvpvklR.png")
                    .tag("test")
                    .into(ivTest2)
            Picasso.get().cancelTag("test")
    

    可以先tag标记下每个请求,然后可以批量处理。
    分别是取消,暂停,恢复。

    1. setLoggingEnabled,isLoggingEnabled
    public void setLoggingEnabled(boolean enabled) {
        loggingEnabled = enabled;
      }
      public boolean isLoggingEnabled() {
        return loggingEnabled;
      }
    

    是否启动日志

    1. getSnapshot
    @SuppressWarnings("UnusedDeclaration") public StatsSnapshot getSnapshot() {
        return stats.createSnapshot();
      }
    

    获取到Picasso的一个快照。

    Picasso.get().snapshot.dump()
    

    然后直接打印。

    ===============BEGIN PICASSO STATS ===============
        Memory Cache Stats
          Max Cache Size: 57521883
          Cache Size: 0
          Cache % Full: 0
          Cache Hits: 0
          Cache Misses: 0
        Network Stats
          Download Count: 0
          Total Download Size: 0
          Average Download Size: 0
        Bitmap Stats
          Total Bitmaps Decoded: 0
          Total Bitmap Size: 0
          Total Transformed Bitmaps: 0
          Total Transformed Bitmap Size: 0
          Average Bitmap Size: 0
          Average Transformed Bitmap Size: 0
    ===============END PICASSO STATS ===============
    

    这个就灰常的方便了,直接看当前Picasso的使用状态

    1. invalidate
      因为Picasso使用了LruCache缓存到内存中,key-value与url-bitmap对应起来(实际上不是保存Bitmap,而是自己封装了另外一个类,但是里面是有Bitmap的,这里先不具体)。invalidate可以移除缓存。
    public void invalidate(@Nullable Uri uri) {
        if (uri != null) {
          cache.clearKeyUri(uri.toString());
        }
      }
    
    1. load
      这个就不说了,上一篇文章介绍了很多了。

    重要对象介绍

    上面简单的了Picasso对象,但是还有很多重要的对象。
    我们可以从Picasso.Builder中去寻找,因为这里面都是我们可以配置的对象。

     public static class Builder {
        private final Context context;
        private Downloader downloader;
        private ExecutorService service;
        private Cache cache;
        private Listener listener;
        private RequestTransformer transformer;
        private List<RequestHandler> requestHandlers;
        private Bitmap.Config defaultBitmapConfig;
    
        private boolean indicatorsEnabled;
        private boolean loggingEnabled;
    ...
    

    这么多可以配置的对象,ndicatorsEnabled,loggingEnabled,context先不说了。

    我们来先来简单介绍下另外几个。

    1. Downloader downloader
      默认实现OkHttp3Downloader
        @NonNull @Override public Response load(@NonNull Request request) throws IOException {
      return client.newCall(request).execute();
      

    }
    ```
    其实是可以自己复写,使用自己的http框架

    1. ExecutorService service
      默认实现PicassoExecutorService
      
      //创建了一个线程池,默认都是3个核心线程,然后还有一个有优先级的阻塞队列
       PicassoExecutorService() {
      super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
          new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
      

    }
    ```
    这里其实还有一个比较有意思的方法

    void adjustThreadCount(NetworkInfo info) {
        if (info == null || !info.isConnectedOrConnecting()) {
          setThreadCount(DEFAULT_THREAD_COUNT);
          return;
        }
        switch (info.getType()) {
          case ConnectivityManager.TYPE_WIFI:
          case ConnectivityManager.TYPE_WIMAX:
          case ConnectivityManager.TYPE_ETHERNET:
            setThreadCount(4);
            break;
          case ConnectivityManager.TYPE_MOBILE:
            switch (info.getSubtype()) {
              case TelephonyManager.NETWORK_TYPE_LTE:  // 4G
              case TelephonyManager.NETWORK_TYPE_HSPAP:
              case TelephonyManager.NETWORK_TYPE_EHRPD:
                setThreadCount(3);
                break;
              case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
              case TelephonyManager.NETWORK_TYPE_CDMA:
              case TelephonyManager.NETWORK_TYPE_EVDO_0:
              case TelephonyManager.NETWORK_TYPE_EVDO_A:
              case TelephonyManager.NETWORK_TYPE_EVDO_B:
                setThreadCount(2);
                break;
              case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
              case TelephonyManager.NETWORK_TYPE_EDGE:
                setThreadCount(1);
                break;
              default:
                setThreadCount(DEFAULT_THREAD_COUNT);
            }
            break;
          default:
            setThreadCount(DEFAULT_THREAD_COUNT);
        }
      }
    

    就是会根据网络的情况使用不同的线程数。可以学习下。
    也可以自定义

    1. Cache cache
      默认使用LruCache
    public LruCache(@NonNull Context context) {
        this(Utils.calculateMemoryCacheSize(context));
      }
    
    ...
    static int calculateMemoryCacheSize(Context context) {
        ActivityManager am = getService(context, ACTIVITY_SERVICE);
        boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
        int memoryClass = largeHeap ? am.getLargeMemoryClass() : am.getMemoryClass();
        // Target ~15% of the available heap.
        return (int) (1024L * 1024L * memoryClass / 7);
      }
    
    

    这里也很有意思,根据当前的app所能使用的内存值获取一个比较合适的缓存内存的最大值。自己可以复写调整。

    1. Listener listener
      没有默认值
    public interface Listener {
      void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception);
    }
    

    很显然是用来全局监听图片加载失败的事件。

    1. RequestTransformer transformer
      默认
    RequestTransformer IDENTITY = new RequestTransformer() {
          @Override public Request transformRequest(Request request) {
            return request;
          }
        };
    

    其实就是一个request的全局的一个转化。默认不转化。

    1. List<RequestHandler> requestHandlers
      前面已经介绍过了默认有很多种requestHandlers,也可以自己定义
    2. Bitmap.Config defaultBitmapConfig
      默认为null
      在requestHandler里面的createBitmapOptions有使用到
     static BitmapFactory.Options createBitmapOptions(Request data) {
        final boolean justBounds = data.hasSize();
        final boolean hasConfig = data.config != null;
        BitmapFactory.Options options = null;
        if (justBounds || hasConfig || data.purgeable) {
          options = new BitmapFactory.Options();
          options.inJustDecodeBounds = justBounds;
          options.inInputShareable = data.purgeable;
          options.inPurgeable = data.purgeable;
        //在这里,如果有config,就配置下,如果没有那么就默认
          if (hasConfig) {
            options.inPreferredConfig = data.config;
          }
        }
        return options;
      }
    
    image.png

    一共这么多选项,可以选择。

    总结

    Picasso用起来也挺爽的,后面有空学习下Glide和Fresco做下对比

    相关文章

      网友评论

        本文标题:Picasso-源码解析(二)

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