美文网首页
图片加载库分析之Glide解析(二)

图片加载库分析之Glide解析(二)

作者: 暴走的小青春 | 来源:发表于2020-02-22 02:11 被阅读0次

上篇说到Glide的缓存流程后,接下来分析下Gilde是如何从网络下载图片并做优化的
由于在上文中从硬盘缓存中已经拿到了对应的data,继而会调用decodeFromData方法

private <Data> Resource<R> decodeFromData(
      DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }

这里的重点还是decodeFromFetcher(data,dataSource)方法

 private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    return runLoadPath(data, dataSource, path);
  }

这里的LoadPath简单来说就流的解析器,一共是gif,drawable,bitmap三种,间接会调用loadWithExceptionList方法,也就是核心的decode方法,来看下Glide是如何为我们在从流到bitmap做优化的

 private Resource<Transcode> loadWithExceptionList(
      DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions)
      throws GlideException {
    Resource<Transcode> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }

    return result;
  }

在分别用不同的解析器调用decode时,我们进去看下

public Resource<Transcode> decode(
      DataRewinder<DataType> rewinder,
      int width,
      int height,
      @NonNull Options options,
      DecodeCallback<ResourceType> callback)
      throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }

可以说Glide分为原始的ResourceType和transformed的ResourceType,transformed应该就是做些圆角的处理,高斯模糊的操作,先来看下decodeResource方法,很明显我们这里是bitmap,所以会走到ByteBufferBitmapDecoder的decode方法中

 @Override
  public Resource<Bitmap> decode(
      @NonNull ByteBuffer source, int width, int height, @NonNull Options options)
      throws IOException {
    InputStream is = ByteBufferUtil.toStream(source);
    return downsampler.decode(is, width, height, options);
  }

再把source转化成常规的InputStream后这里就等同于从网络下拿到了InputStream转化成bitmap的操作了
间接会调用decodeFromWrappedStreams的方法
方法中其实做了这几个操作,由于方法太长,就贴出部分

  private static int[] getDimensions(
      ImageReader imageReader,
      BitmapFactory.Options options,
      DecodeCallbacks decodeCallbacks,
      BitmapPool bitmapPool)
      throws IOException {
    options.inJustDecodeBounds = true;
    decodeStream(imageReader, options, decodeCallbacks, bitmapPool);
    options.inJustDecodeBounds = false;
    return new int[] {options.outWidth, options.outHeight};
  }

先把inJustDecodeBounds设置为true,这样在native层就不会生成java的byte数组的图片了,只会把宽高返回
而后这里的inBitmap属性就是为了减少开辟空间,而复用bitmap的
而bitmapPool正式存放这个inBitmap的
接下来就是关于部分手机的图片旋转的操作了

int orientation = imageReader.getImageOrientation();
    int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
    boolean isExifOrientationRequired = TransformationUtils.isExifOrientationRequired(orientation);

    int targetWidth =
        requestedWidth == Target.SIZE_ORIGINAL
            ? (isRotationRequired(degreesToRotate) ? sourceHeight : sourceWidth)
            : requestedWidth;
    int targetHeight =
        requestedHeight == Target.SIZE_ORIGINAL
            ? (isRotationRequired(degreesToRotate) ? sourceWidth : sourceHeight)
            : requestedHeight;

最后会根据不同的ImageType去缩放图片,然后根据图片是否是jpg,或者webp,或者png去设置inSampleSize

// Here we mimic framework logic for determining how inSampleSize division is rounded on various
    // versions of Android. The logic here has been tested on emulators for Android versions 15-26.
    // PNG - Always uses floor
    // JPEG - Always uses ceiling
    // Webp - Prior to N, always uses floor. At and after N, always uses round.
    options.inSampleSize = powerOfTwoSampleSize;
    int powerOfTwoWidth;
    int powerOfTwoHeight;
    if (imageType == ImageType.JPEG) {
      // libjpegturbo can downsample up to a sample size of 8. libjpegturbo uses ceiling to round.
      // After libjpegturbo's native rounding, skia does a secondary scale using floor
      // (integer division). Here we replicate that logic.
      int nativeScaling = Math.min(powerOfTwoSampleSize, 8);
      powerOfTwoWidth = (int) Math.ceil(orientedSourceWidth / (float) nativeScaling);
      powerOfTwoHeight = (int) Math.ceil(orientedSourceHeight / (float) nativeScaling);
      int secondaryScaling = powerOfTwoSampleSize / 8;
      if (secondaryScaling > 0) {
        powerOfTwoWidth = powerOfTwoWidth / secondaryScaling;
        powerOfTwoHeight = powerOfTwoHeight / secondaryScaling;
      }

可以说远比我们自己设置的要靠谱的多,而且在其线程池做操作的,我们要做的就是告诉Glide图片的宽高就行了
最后如果图片解析失败了,Glide还会到bitmapPool中去取图片

int sourceWidth = options.outWidth;
    int sourceHeight = options.outHeight;
    String outMimeType = options.outMimeType;
    final Bitmap result;
    TransformationUtils.getBitmapDrawableLock().lock();
    try {
      result = imageReader.decodeBitmap(options);
    } catch (IllegalArgumentException e) {
      IOException bitmapAssertionException =
          newIoExceptionForInBitmapAssertion(e, sourceWidth, sourceHeight, outMimeType, options);
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(
            TAG,
            "Failed to decode with inBitmap, trying again without Bitmap re-use",
            bitmapAssertionException);
      }
      if (options.inBitmap != null) {
        try {
          bitmapPool.put(options.inBitmap);
          options.inBitmap = null;
          return decodeStream(imageReader, options, callbacks, bitmapPool);
        } catch (IOException resetException) {
          throw bitmapAssertionException;
        }
      }
      throw bitmapAssertionException;
    } finally {
      TransformationUtils.getBitmapDrawableLock().unlock();
    }

    return result;

最后返回了bitmap

    Bitmap downsampled = decodeStream(imageReader, options, callbacks, bitmapPool);
    callbacks.onDecodeComplete(bitmapPool, downsampled);

最后通过callCallbackOnResourceReady返回给了调用者

 @SuppressWarnings("WeakerAccess")
  @Synthetic
  @GuardedBy("this")
  void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      // This is overly broad, some Glide code is actually called here, but it's much
      // simpler to encapsulate here than to do so at the actual call point in the
      // Request implementation.
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

在imageView的target中

 private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }

设置了imageview。
至此,Glide从网络加载图片的核心部分也就到此结束了,其实还有很多细节没有分析到,以后可能在用的途中又需要的话再去分析吧。

相关文章

  • Glide基本使用

    参考 Android图片加载框架最全解析(一),Glide的基本用法Google推荐的图片加载库Glide介绍 思...

  • 图片加载库分析之Glide解析(二)

    继上篇说到Glide的缓存流程后,接下来分析下Gilde是如何从网络下载图片并做优化的由于在上文中从硬盘缓存中已经...

  • Android 库 Glide

    【Android 库 Glide】 引用 Android图片加载框架最全解析(一),Glide的基本用法Andro...

  • Android 三方框架原理

    Android图片加载框架最全解析(一),Glide的基本用法 Android图片加载框架最全解析(二),从源码的...

  • Glide->02Bitmap复用

    参考文章: Glide源码分析之缓存处理 Glide缓存机制 一、源码解析: 如果是第一次加载图片, 即不存在缓存...

  • 图片加载库分析之Glide解析(一)

    图片加载框架Glide在我们实战中,运用的很频繁,但是glide为我们做的太多了,以至于我们忽略了处理图片很多基础...

  • 请求数据

    使用到 Okhttp网络请求 Glide图片加载库 Json解析之Gson OKHttp网络请求的封装:我用的是O...

  • Android 一些开源库

    网络请求 :OkHttp Json解析:Gson SQLite数据库框架:LitePal 图片加载框架:Glide...

  • Android图片加载框架Glide源码解析(二)

    Glide的图片加载流程 上一章节Android图片加载框架Glide源码解析(一)中讲Glide的基本使用,对于...

  • 开源框架_01Glide

    参考文章 : Android图片加载框架最全解析(一), Glide的基本用法 Android图片加载框架最全解析...

网友评论

      本文标题:图片加载库分析之Glide解析(二)

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