美文网首页
picasso源码解析

picasso源码解析

作者: changchengfeng | 来源:发表于2017-09-19 22:16 被阅读28次

    picasso的使用非常简单

    Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
    

    1.0 单例模式 生成一个Picasso对象

     public static Picasso with(Context context) {
        if (singleton == null) {
          synchronized (Picasso.class) {
            if (singleton == null) {
              singleton = new Builder(context).build();
            }
          }
        }
        return singleton;
      }
    

    2.0 构建Picasso对象时进行初始化各个成员变量

    public Picasso build() {
          Context context = this.context;
    // 2.1 实现Downloader的接口,这个接口主要有以下抽象方法
    // Response load(Uri uri, int networkPolicy) throws IOException;
    // 此Response非OkHttp里面的Response,而是Downloader的内部类,主要存储了Bitmap,InputStream对象 图片数据
    
          if (downloader == null) {
            downloader = Utils.createDefaultDownloader(context);
          }
    // 2.2 内存缓存,使用最近最少使用算法
          if (cache == null) {
            cache = new LruCache(context);
          }
    // 2.3 构建线程池
          if (service == null) {
            service = new PicassoExecutorService();
          }
    // 2.4 对Request对象(非OkHttp里面的Request)进行转换接口,默认不做任何操作,给用户自定义
          if (transformer == null) {
            transformer = RequestTransformer.IDENTITY;
          }
          
    // 2.5 创建Stats对象主要用来统计的,日志记录。
    
          Stats stats = new Stats(cache);
    // 2.6 创建Dispatcher对象
          Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
          
    // 2.7 生成Picasso对象
          return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
              defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
        }
    

    2.1.1 若有OkHttpClient类就使用OkHttp库进行网络请求下载图片,否则使用UrlConnection

      static Downloader createDefaultDownloader(Context context) {
        try {
          Class.forName("com.squareup.okhttp.OkHttpClient");
          return OkHttpLoaderCreator.create(context);
        } catch (ClassNotFoundException ignored) {
        }
        return new UrlConnectionDownloader(context);
      }
    

    2.1.2 创建OkHttpDownloader对象,并设置硬盘缓存,硬盘缓存大小为硬盘的50分之1 缓存大小为最大50M,最小5M.

      private static class OkHttpLoaderCreator {
        static Downloader create(Context context) {
          return new OkHttpDownloader(context);
        }
      }
      
    public OkHttpDownloader(final Context context) {
        this(Utils.createDefaultCacheDir(context));
      }
      
    
    static File createDefaultCacheDir(Context context) {
        File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE);
        if (!cache.exists()) {
          //noinspection ResultOfMethodCallIgnored
          cache.mkdirs();
        }
        return cache;
      }
    public OkHttpDownloader(final File cacheDir) {
        this(cacheDir, Utils.calculateDiskCacheSize(cacheDir));
      }
      
      static long calculateDiskCacheSize(File dir) {
        long size = MIN_DISK_CACHE_SIZE;
    
        try {
          StatFs statFs = new StatFs(dir.getAbsolutePath());
          long available = ((long) statFs.getBlockCount()) * statFs.getBlockSize();
          // Target 2% of the total space.
          size = available / 50;
        } catch (IllegalArgumentException ignored) {
        }
    
        // Bound inside min/max size for disk cache.
        return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
      }
      public OkHttpDownloader(final File cacheDir, final long maxSize) {
        this(defaultOkHttpClient());
        try {
          client.setCache(new com.squareup.okhttp.Cache(cacheDir, maxSize));
        } catch (IOException ignored) {
        }
      }
    

    2.2.1 内存缓存,大小为app最大使用内存的7分之1

      public LruCache(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 = am.getMemoryClass();
        if (largeHeap && SDK_INT >= HONEYCOMB) {
          memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
        }
        // Target ~15% of the available heap.
        return 1024 * 1024 * memoryClass / 7;
      }
    

    2.3.1 创建线程池

      PicassoExecutorService() {
        super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
            new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
      }
    

    2.4.1. 默认不做任何操作,用户可自定义

        RequestTransformer IDENTITY = new RequestTransformer() {
          @Override public Request transformRequest(Request request) {
            return request;
          }
        };
      }
    

    2.5.1.创建一个后台线程,进行记录Picasso运行状态

      Stats(Cache cache) {
        this.cache = cache;
        this.statsThread = new HandlerThread(STATS_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
        this.statsThread.start();
        Utils.flushStackLocalLeaks(statsThread.getLooper());
        this.handler = new StatsHandler(statsThread.getLooper(), this);
      }
    

    2.6.1 创建Dispatcher对象

      Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
          Downloader downloader, Cache cache, Stats stats) {
    ...
        this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
        this.downloader = downloader;
        this.mainThreadHandler = mainThreadHandler;
    ...
      }
    

    2.7.1 创建7个RequestHandler 处理不同数据来源的生成Result包含Bitmap,InputStream对象

    RequestHandler是一个抽象类 抽象方法如下

    public abstract Result load(Request request, int networkPolicy) throws IOException;
     public abstract boolean canHandleRequest(Request data);
    

    这7个RequestHandler,除ResourceRequestHandler大多用Request的Uri对象进行区分,我们也可以实现以上抽象方法自定义自己的RequestHandler进行扩展,以便处理这7个以外的特殊图片数据来源

    Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
          RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
          Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
    ...
    
        int builtInHandlers = 7; // Adjust this as internal handlers are added or removed.
        int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
        List<RequestHandler> allRequestHandlers =
            new ArrayList<RequestHandler>(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);
    ...
      }
    

    以上就是第一次调用with方法所做的操作

    3.0. load方法

    创建RequestCreator对象,配置好uri,resourceId;若是从网络中读取图片,resourceId为0

      public RequestCreator load(String path) {
        if (path == null) {
          return new RequestCreator(this, null, 0);
        }
        if (path.trim().length() == 0) {
          throw new IllegalArgumentException("Path must not be empty.");
        }
        // 
        return load(Uri.parse(path));
      }
      
      public RequestCreator load(Uri uri) {
      
      // 
        return new RequestCreator(this, uri, 0);
      }
      
      
     RequestCreator(Picasso picasso, Uri uri, int resourceId) {
        if (picasso.shutdown) {
          throw new IllegalStateException(
              "Picasso instance already shut down. Cannot submit new requests.");
        }
        this.picasso = picasso;
    // 
        this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
      }
     // 
    
      Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
          this.uri = uri;
          this.resourceId = resourceId;
          this.config = bitmapConfig;
        }
    

    4. into 方法

    4.1. 图片绑定到ImageView

      public void into(ImageView target) {
        into(target, null);
      }
    

    4.2 into方法的解析

    public void into(ImageView target, Callback callback) {
        long started = System.nanoTime();
        // 检查是否是在主线程中操作UI
        checkMain();
    
        if (target == null) {
          throw new IllegalArgumentException("Target must not be null.");
        }
    // 是否设置了uri,或者resourceId,在load方法已经设置了uri,为false不执行
        if (!data.hasImage()) {
          picasso.cancelRequest(target);
          if (setPlaceholder) {
            setPlaceholder(target, getPlaceholderDrawable());
          }
          return;
        }
    // deferred 默认为false,不执行。除非调用了fit()方法
        if (deferred) {
          if (data.hasSize()) {
            throw new IllegalStateException("Fit cannot be used with resize.");
          }
          int width = target.getWidth();
          int height = target.getHeight();
          if (width == 0 || height == 0) {
            if (setPlaceholder) {
              setPlaceholder(target, getPlaceholderDrawable());
            }
            picasso.defer(target, new DeferredRequestCreator(this, target, callback));
            return;
          }
          data.resize(width, height);
        }
    
    // 4.2.1
        Request request = createRequest(started);
        
    // 根据Request的特性生成独一无二的requestKey
        String requestKey = createKey(request);
    
    // 4.2.2 若未设置memoryPolicy 此为ture
        if (shouldReadFromMemoryCache(memoryPolicy)) {
        // 通过requestKey从内存缓存中获取,第一次网络请求未存储获取不到,bitmap为null
          Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
          if (bitmap != null) {
            picasso.cancelRequest(target);
            setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
    ...
            if (callback != null) {
              callback.onSuccess();
            }
            return;
          }
        }
    // 设置Placeholder,若未Placeholder显示空白,等待下载图片时 的替代图片显示到ImageView
        if (setPlaceholder) {
          setPlaceholder(target, getPlaceholderDrawable());
        }
    // 4.2.3 
        Action action =
            new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
                errorDrawable, requestKey, tag, callback, noFade);
    // 4.2.4
        picasso.enqueueAndSubmit(action);
      }
    

    4.2.1 生成Request对象

      private Request createRequest(long started) {
       // 生成独一无二的ID
        int id = nextId.getAndIncrement();
      // 3.3 生成的Request.Builder
        Request request = data.build();
        request.id = id;
        request.started = started;
    
        boolean loggingEnabled = picasso.loggingEnabled;
        if (loggingEnabled) {
          log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
        }
    //  参考2.4 RequestTransformer对象进行转换处理Request,id和started开始时间不变
        Request transformed = picasso.transformRequest(request);
        if (transformed != request) {
          // If the request was changed, copy over the id and timestamp from the original.
          transformed.id = id;
          transformed.started = started;
    
          if (loggingEnabled) {
            log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
          }
        }
    
        return transformed;
      }
    

    4.2.2 获取存储策略

      /** Skips memory cache lookup when processing a request. */
      NO_CACHE(1 << 0),
      /**
       * Skips storing the final result into memory cache. Useful for one-off requests
       * to avoid evicting other bitmaps from the cache.
       */
      NO_STORE(1 << 1);
    
      static boolean shouldReadFromMemoryCache(int memoryPolicy) {
        return (memoryPolicy & MemoryPolicy.NO_CACHE.index) == 0;
      }
    
      static boolean shouldWriteToMemoryCache(int memoryPolicy) {
        return (memoryPolicy & MemoryPolicy.NO_STORE.index) == 0;
      }
    

    4.2.3 创建ImageViewAction对象

      ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
          int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
          Callback callback, boolean noFade) {
        super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,
            tag, noFade);
        this.callback = callback;
      }
    

    4.2.4 调用enqueueAndSubmit方法

      void enqueueAndSubmit(Action action) {
        Object target = action.getTarget();
        if (target != null && targetToAction.get(target) != action) {
          // This will also check we are on the main thread.
          cancelExistingRequest(target);
          targetToAction.put(target, action);
        }
        submit(action);
      }
      
        void submit(Action action) {
        dispatcher.dispatchSubmit(action);
      }
      
        void dispatchSubmit(Action action) {
        handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
      }
      
          @Override public void handleMessage(final Message msg) {
          switch (msg.what) {
            case REQUEST_SUBMIT: {
              Action action = (Action) msg.obj;
              dispatcher.performSubmit(action);
              break;
            }
            
      void performSubmit(Action action) {
        performSubmit(action, true);
      }
      
      void performSubmit(Action action, boolean dismissFailed) {
      // pausedTags暂停对象集合 若是Action设置了tag 同一个对象就会暂停执行
        if (pausedTags.contains(action.getTag())) {
          pausedActions.put(action.getTarget(), action);
    ...
    ...
          return;
        }
    // hunterMap若是存储了BitmapHunter对象就不用生成BitmapHunter,第一次未存储未null
        BitmapHunter hunter = hunterMap.get(action.getKey());
        if (hunter != null) {
          hunter.attach(action);
          return;
        }
    
        if (service.isShutdown()) {
    ...
    ...
          return;
        }
    // 4.2.4.1
        hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    // 4.2.4.2
    // 添加到线程池会执行BitmapHunter的 run()方法
        hunter.future = service.submit(hunter);
    // 放入hunterMap,下次就可直接使用
        hunterMap.put(action.getKey(), hunter);
    // 若是之前失败过,移除掉失败的ImageView的对应的BitmapHunter对象
        if (dismissFailed) {
          failedActions.remove(action.getTarget());
        }
    ...
    ...
      }
    

    4.2.4.1 构建BitmapHunter对象

      static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
          Action action) {
        Request request = action.getRequest();
        List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
    
        for (int i = 0, count = requestHandlers.size(); i < count; i++) {
          RequestHandler requestHandler = requestHandlers.get(i);
    // 参考 2.7.1设置的7个RequestHandler 
    // 每个RequestHandler都实现了canHandleRequest,判断处理不同的图片数据源
    // 我们设置的是通过 NetworkRequestHandler处理
          if (requestHandler.canHandleRequest(request)) {
            return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
          }
        }
    
        return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
      }
      
    
    
    
        BitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action,
          RequestHandler requestHandler) {
        this.sequence = SEQUENCE_GENERATOR.incrementAndGet();
        this.picasso = picasso;
        this.dispatcher = dispatcher;
        this.cache = cache;
        this.stats = stats;
        this.action = action;
        this.key = action.getKey();
        this.data = action.getRequest();
        this.priority = action.getPriority();
        this.memoryPolicy = action.getMemoryPolicy();
        this.networkPolicy = action.getNetworkPolicy();
        this.requestHandler = requestHandler;
        this.retryCount = requestHandler.getRetryCount();
      }
      
     
    

    4.2.4.2 添加到线程池会执行BitmapHunter的 run()方法

     
     @Override public void run() {
        try {
    ...
        // 4.2.4.2.1
          result = hunt();
          if (result == null) {
            dispatcher.dispatchFailed(this);
          } else {
        // 4.2.4.2.2
            dispatcher.dispatchComplete(this);
          }
    ...
    
      }
    
    
    4.2.4.2.1 hunt方法解析
    
      Bitmap hunt() throws IOException {
        Bitmap bitmap = null;
     //  从内存缓存中获取,第一次未缓存bitmap为null
        if (shouldReadFromMemoryCache(memoryPolicy)) {
          bitmap = cache.get(key);
          if (bitmap != null) {
    ...
            return bitmap;
          }
        }
    //  NetworkRequestHandler设置的retryCount为2 
        data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    // 4.2.4.2.1.1
        RequestHandler.Result result = requestHandler.load(data, networkPolicy);
        if (result != null) {
          loadedFrom = result.getLoadedFrom();
          exifRotation = result.getExifOrientation();
    
          bitmap = result.getBitmap();
    
        
          //okhttp下载,bitmap==null,从流中加载生成bitmap
          if (bitmap == null) {
            InputStream is = result.getStream();
            try {
              bitmap = decodeStream(is, data);
            } finally {
              Utils.closeQuietly(is);
            }
          }
        }
    
        if (bitmap != null) {
    ...
        // RequestCreator并未设置平移或者旋转,此为false
          if (data.needsTransformation() || exifRotation != 0) {
            synchronized (DECODE_LOCK) {
              if (data.needsMatrixTransform() || exifRotation != 0) {
                bitmap = transformResult(data, bitmap, exifRotation);
    ...
              }
              if (data.hasCustomTransformations()) {
                bitmap = applyCustomTransformations(data.transformations, bitmap);
    ...
              }
            }
    ...
          }
        }
    
        return bitmap;
      }
    
    4.2.4.2.1.1 load方法解析
      @Override public Result load(Request request, int networkPolicy) throws IOException {
    // 利用OkHttpDownloader下载图片,参看2.1 及OKHttp的使用
        Response response = downloader.load(request.uri, request.networkPolicy);
        if (response == null) {
          return null;
        }
    
        Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;
    
        Bitmap bitmap = response.getBitmap();
        if (bitmap != null) {
          return new Result(bitmap, loadedFrom);
        }
    
        InputStream is = response.getInputStream();
        if (is == null) {
          return null;
        }
    ...
        return new Result(is, loadedFrom);
      }
    
    4.2.4.2.2 完成Bitmap加载到ImageView
        // 参看2.6.1 此handler为DispatcherHandler会发送消息到为主线程处理
      void dispatchComplete(BitmapHunter hunter) {
        handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
      }
      
         case HUNTER_COMPLETE: {
              BitmapHunter hunter = (BitmapHunter) msg.obj;
              //
              dispatcher.performComplete(hunter);
              break;
            }
            
      void performComplete(BitmapHunter hunter) {
      // 根据MemoryPolicy会把下载好的图片放入到内存缓存当中
        if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
          cache.set(hunter.getKey(), hunter.getResult());
        }
        hunterMap.remove(hunter.getKey());
        // 
        batch(hunter);
     ...
      }
      
        private void batch(BitmapHunter hunter) {
        if (hunter.isCancelled()) {
          return;
        }
        batch.add(hunter);
        if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
        //
          handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
        }
      }
      
        case HUNTER_DELAY_NEXT_BATCH: {
        //
              dispatcher.performBatchComplete();
              break;
            }
            
      void performBatchComplete() {
        List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch);
        batch.clear();
        // 
        mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
        logBatch(copy);
      }
      
      
      case HUNTER_BATCH_COMPLETE: {
              @SuppressWarnings("unchecked") List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
              //noinspection ForLoopReplaceableByForEach
              for (int i = 0, n = batch.size(); i < n; i++) {
                BitmapHunter hunter = batch.get(i);
                // 
                hunter.picasso.complete(hunter);
              }
              break;
            }
            
     void complete(BitmapHunter hunter) {
        Action single = hunter.getAction();
    ...
    
        if (single != null) {
        //
          deliverAction(result, from, single);
        }
    
    ...
      }
      
        private void deliverAction(Bitmap result, LoadedFrom from, Action action) {
    ...
    //
          action.complete(result, from);
    ...
      }
      
      
        @Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
    ...
        ImageView target = this.target.get();
        if (target == null) {
          return;
        }
        Context context = picasso.context;
        boolean indicatorsEnabled = picasso.indicatorsEnabled;
        //
        PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
    ...
      }
      
      
        static void setBitmap(ImageView target, Context context, Bitmap bitmap,
          Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
    ...
        PicassoDrawable drawable =
            new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
        // 终于看到了我们熟悉的ImageView.setImageDrawable()方法设置图片
        target.setImageDrawable(drawable);
      }
    

    相关文章

      网友评论

          本文标题:picasso源码解析

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