Picasso源码快读

Picasso是目前android最流行的图片加载框架之一,此篇的内容就是简略的介绍一下Picasso的实现


结构

简单整理一下各个类直接的关系,大体就是这个样子

其中的核心类是

    Picasso  RequestCreator  RequestHandler Action  Dispatcher

其中Picasso以单例实现,外部通过load方法创建并获取一个RequestCreator 实例,后续逻辑控制在这个RequestCreator

实例中。此时,RequestCreator 的职责已经超过其命名,更像是这次图片获取任务的Manager或者Holder。


每个ImageView在into之后,会对应生成一个DeferredRequestCreator,DeferredRequestCreator 会持有一个RequestCreator,并且监控View的onPreDraw,在此时开始图片加载。

RequestCreator内部创建特定Action经Picasso交由Dispatcher执行操作BitmapHunter。

Picasso创建时会一同创建所有可能需要的RequestHandler,创建时通过入参可添加,并在创建BitmapHunter时选择合适的RequestHandler使用。

BitmapHunter本身是一个Runnable,其中主要方法是hunt。

Bitmap hunt() throws IOException {

    Bitmap bitmap = null;

    if (shouldReadFromMemoryCache(memoryPolicy)) {

      bitmap = cache.get(key);

      if (bitmap != null) {

        stats.dispatchCacheHit();

        loadedFrom = MEMORY;

        if (picasso.loggingEnabled) {

          log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");

        }

        return bitmap;

      }

    }

    networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;

    RequestHandler.Result result = requestHandler.load(data, networkPolicy);

    if (result != null) {

      loadedFrom = result.getLoadedFrom();

      exifOrientation = result.getExifOrientation();

      bitmap = result.getBitmap();

      // If there was no Bitmap then we need to decode it from the stream.

      if (bitmap == null) {

        Source source = result.getSource();

        try {

          bitmap = decodeStream(source, data);

        } finally {

          try {

            //noinspection ConstantConditions If bitmap is null then source is guranteed non-null.

            source.close();

          } catch (IOException ignored) {

          }

        }

      }

    }

    if (bitmap != null) {

      if (picasso.loggingEnabled) {

        log(OWNER_HUNTER, VERB_DECODED, data.logId());

      }

      stats.dispatchBitmapDecoded(bitmap);

      if (data.needsTransformation() || exifOrientation != 0) {

        synchronized (DECODE_LOCK) {

          if (data.needsMatrixTransform() || exifOrientation != 0) {

            bitmap = transformResult(data, bitmap, exifOrientation);

            if (picasso.loggingEnabled) {

              log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());

            }

          }

          if (data.hasCustomTransformations()) {

            bitmap = applyCustomTransformations(data.transformations, bitmap);

            if (picasso.loggingEnabled) {

              log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");

            }

          }

        }

        if (bitmap != null) {

          stats.dispatchBitmapTransformed(bitmap);

        }

      }

    }

    return bitmap;

  }


static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,

      Action action) {

    Request request = action.getRequest();

    List requestHandlers = picasso.getRequestHandlers();

    // Index-based loop to avoid allocating an iterator.

    //noinspection ForLoopReplaceableByForEach

    for (int i = 0, count = requestHandlers.size(); i < count; i++) {

      RequestHandler requestHandler = requestHandlers.get(i);

      if (requestHandler.canHandleRequest(request)) {

        return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);

      }

    }

    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);

  }

static Bitmap decodeStream(Source source, Request request) throws IOException {

    BufferedSource bufferedSource = Okio.buffer(source);

    boolean isWebPFile = Utils.isWebPFile(bufferedSource);

    boolean isPurgeable = request.purgeable && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;

    BitmapFactory.Options options = RequestHandler.createBitmapOptions(request);

    boolean calculateSize = RequestHandler.requiresInSampleSize(options);

    // We decode from a byte array because, a) when decoding a WebP network stream, BitmapFactory

    // throws a JNI Exception, so we workaround by decoding a byte array, or b) user requested

    // purgeable, which only affects bitmaps decoded from byte arrays.

    if (isWebPFile || isPurgeable) {

      byte[] bytes = bufferedSource.readByteArray();

      if (calculateSize) {

        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

        RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,

            request);

      }

      return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

    } else {

      InputStream stream = bufferedSource.inputStream();

      if (calculateSize) {

        // TODO use an InputStream that buffers with Okio...

        MarkableInputStream markStream = new MarkableInputStream(stream);

        stream = markStream;

        markStream.allowMarksToExpire(false);

        long mark = markStream.savePosition(1024);

        BitmapFactory.decodeStream(stream, null, options);

        RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,

            request);

        markStream.reset(mark);

        markStream.allowMarksToExpire(true);

      }

      Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

      if (bitmap == null) {

        // Treat null as an IO exception, we will eventually retry.

        throw new IOException("Failed to decode stream.");

      }

      return bitmap;

    }

  }

可以看到其中decode,获取result等操作都会使用创建时置入RequestHandler进行处理。

以上就是Picasso的大体结构及核心逻辑

你可能感兴趣的:(Picasso源码快读)