Android 图片加载框架Glide4.0源码彻底解析(二)

写在以前html

上一篇博文写的是Android 图片加载框架Glide4.0源码彻底解析(一),主要分析了Glide4.0源码中的with方法和load方法,本来打算是一块儿发布的,可是因为into方法复杂性远不是前两个方法所能比拟的,又不肯意马马虎虎的随便应付的写做,仍是保持一向的一步步深刻的讲解,因此就提早发布了一篇,以减小篇幅。java

正文python

这篇是讲Glide源码中into方法的实现原理,能够说with和load方法只是作了前期的初始化配置工做,而真正意义上的图片加载就是在into方法中实现的,因此该方法的复杂程度是能够想象的,仍是依照我以前的写做习惯,一步步的分析,不留下任何的盲点给你们带来困惑,那么下面就开始吧。缓存

Glide 源码分析

into()

前面两个方法把所需的基础配置基本已作好,那么接下来就是真正的要去加载资源了,那么咱们来看看吧:微信

首先进去into方法中:网络

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions.optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions.optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(context.buildImageViewTarget(view, transcodeClass));
  }

主要是为requestOptions 作一些配置,这个配置时根据View的属性而来的。app

而后调用GlideContext的buildImageViewTarget方法,并把view和transcodeClass传递进去来构造一个viewTarget的对象,跟进去看看:框架

直接的调用imageViewTargetFactory的buildTarget方法,而后看下buildTarget的源码:ide

还记得我屡次提醒transcodeClass是什么吗?没错就是Drawable.class,就是在这个分支中使用到,那么在buildTarget中就是建立一个DrawableImageViewTarget对象,并它view传递进去,DrawableImageViewTarget继承于ImageViewTarget,又把view传递到了ViewTarget中,最终把view存放到了ViewTarget中的view变量中,而且还建立了一个SizeDeterminer对象:oop

ok,这就是咱们的ImageView的最终去向,知道了view的去向,咱们在返回到RequestBuilder中,建立个DrawableImageViewTarget对象后,又把它重定向到into方法中:

这个方法是很是重要的,必需要理解清楚,其实真正的理解好了也就很简单的了:

首先,从target中调用getRequest方法获取Request请求,这个getRequest方法是在ViewTarget父类中:

它首先从View中获取tag标识,可是咱们从未为view设置标识,它也就不存在什么标识,因此getTag方法会返回一个null值,由此request也就是一个null空值。

在从taget中获取不到request,那么就须要为它去构造request对象,因此它调用了buildRequest:

private Request buildRequest(Target<TranscodeType> target) {
    return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(),
        requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight());
  }

buildRequest方法又调用了buildRequestRecursive方法:

private Request buildRequestRecursive(Target<TranscodeType> target,
      @Nullable ThumbnailRequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority, int overrideWidth, int overrideHeight) {
    ...
      return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
          overrideWidth, overrideHeight);
  }

buildRequestRecursive作了一堆判断,最终会调用obtainRequest方法:

在这里它直接的调用SingleRequest.obtain方法,并返回一个Request对象,由此咱们看到最终是调用到SingleRequest来真正的构造Request对象:

public static <R> SingleRequest<R> obtain(
      GlideContext glideContext,
      Object model,
      Class<R> transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      RequestListener<R> requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory) {
    @SuppressWarnings("unchecked") SingleRequest<R> request =
        (SingleRequest<R>) POOL.acquire();
    if (request == null) {
      request = new SingleRequest<>();
    }
    request.init(
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }

由obtain方法看到,建立了一个SingleRequest对象,并调用它的init方法来进行初始化操做。

ok,到此Request建立完毕,来看看它拥有哪些成员:

让咱们再回到into方法中,建立了Request对象后,把它设置给咱们的target,最终则是调用setTag方法为view设置tag:

private void setTag(@Nullable Object tag) {
    if (tagId == null) {
      isTagUsedAtLeastOnce = true;
      view.setTag(tag);
    } else {
      view.setTag(tagId, tag);
    }
  }

设置完毕以后将会调用requestManager中的track方法:

void track(Target<?> target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

track方法中分别把target和request添加到targetTracker和requestTracker追踪器中。

而后来看看runRequest方法:

它将会调用Request对象的begin方法来企图开启咱们的请求,咱们知道request其实就是咱们的SingleRequest对象,那么到它的begin方法中看看到底作了哪些事情:

@Override
  public void begin() {
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

首先,它判断model是否为空,若是请求url为空的话,那就不用请求了,直接调用onLoadFailed加载失败。

而后,调用onSizeReady方法,真正的资源加载就是从这个方法中开始的。

最后,根据Status对象状态和是否有占位图来设置加载过程当中的占位图。

那么重点就是在onSizeReady方法中了,咱们来详细的看看它的源码:

@Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadStatus = engine.load(
        glideContext,
        model,
        requestOptions.getSignature(),
        this.width,
        this.height,
        requestOptions.getResourceClass(),
        transcodeClass,
        priority,
        requestOptions.getDiskCacheStrategy(),
        requestOptions.getTransformations(),
        requestOptions.isTransformationRequired(),
        requestOptions.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

onSizeReady方法中首先把State状态更改成RUNNING,而后获取到ImageView的宽高属性值,这个属性值就是要加载的图片的宽高,顺便提一句,Glide框架会根据请求加载图片的ImageView的宽高来进行加载相对应的宽高图片,每次根据view的大小加载的图片是不必定同样的。最后调用engine中的load方法,咱们再来看看load方法的源码:

public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = LogTime.getLogTime();

    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    EngineJob<?> current = jobs.get(key);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
    DecodeJob<R> decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        onlyRetrieveFromCache,
        options,
        engineJob);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(decodeJob);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

哇吼,全部重要的东西都在这里了,解析下:

①:判断是否在主线程运行,说明到目前为止仍是在主线程执行的,并无真正的开启子线程。

②:经过keyFactory工厂来构建一个EngineKey对象,key关联着model,也就是url,它很根据model,view的宽高等等属性来构建一个EngineKey对象,这个对象能够用来指定缓存地址,能够用来从缓存中查找资源等。

③:根据建立的key对象分别调用loadFromCache和loadFromActiveResources方法来从内存中查找是否有缓存资源,若是有,则回调cb.onResourceReady来直接设置图片了。

④:分别使用engineJobFactory和decodeJobFactory构建EngineJob和DecodeJob对象,这两个对象是真正的加载资源的两个重要类,EngineJob对象负责开启线程去加载资源,而且加载得资源后转换到主线程并进行回调;DecodeJob是真正的执行者,它就是去网络加载资源的地方,EngineJob开启线程,真正执行的是DecodeJob,DecodeJob以后完毕以后叫道EngineJob去分发回调。这就是这两个类的关系。

⑤:EngineJob和DecodeJob的构建是基本一致的,咱们看看比较复杂的DecodeJob的构建:在build方法中,首先经过pool来建立一个DecodeJob对象,而后调用DecodeJob对象的init方法进行初始化,在初始化中值得注意的是调用了decodeHelper对象的init方法。decodeHelper方法是DecodeJob的重要辅助类,后面咱们会详细的接触它。

⑥:上面也提到回调,这里先cb添加到engineJob.addCallback();中,而后调用EngineJob的start方法来开启线程。

咱们再来看看start方法中的源码:

start方法中将会调用GlideExecutor的execute方法:

execute中正式的开启了线程池进行加载资源。由此咱们也正式的由主线程转到了子线程中。

上面咱们也分析了,真正执行线程的是在DecodeJob类中,那么咱们去看看的run方法是怎么执行的:

run方法中调用runWrapped方法,主要就是在它里面执行的,来看看它的源码:

咱们知道,在构造DecodeJob时调用init方法是runReason被赋值为INITIALIZE值,由此它将会进入到INITIALIZE分支中,调用getNextStage方法:

在getNextStage方法中经错几回的经转会返回Stage.SOURCE值,而后在调用getNextGenerator方法来获取当前的currentGenerator对象,咱们在来看看获取的这个currentGenerator究竟是什么?

getNextGenerator方法中根据stage值来建立对象,由此咱们能够知道currentGenerator是一个SourceGenerator对象,那么咱们继续往下走,来看看runGenerators方法:

runGenerators最重要的就是执行了currentGenerator的startNext方法,这里将会真正的去加载网络资源:

咱们从上面知道currentGenerator就是SourceGenerator对象,那么咱们去看看SourceGenerator中startNext的实现:

到这里就太关键了,由于不少人都死在这一步上,根本找不到是怎么去加载资源的,是怎么执行到咱们熟悉的HttpURLConnection的,那么到这里你千万不能分神,稍微分神就会转迷糊了,哈哈,那么接下来就开始分析吧:

因为咱们在建立SourceGenerator对象时,只是传递了DecodeHelper和回调cb对象,其余的一切初始化操做都是不存在的,因此在startNext中,前面的两个判断是不成立的,主要是看while循环里面的内容:

while循环中首先调用hasNextModelLoader进行判断,咱们来看下hasNextModelLoader的内容,这里必须集中精力理解清楚,否则确定不知所云:

private boolean hasNextModelLoader() {
    return loadDataListIndex < helper.getLoadData().size();
  }

在hasNextModelLoader中它要去helper加载数据,调用getLoadData方法,咱们跟进去看看:

在getLoadData方法中是调用GlideContext中的getRegistry方法来回去Registry对象,它是在Glide的构造方法中建立的,并且注册添加了不少解析器还记得吗?不记得的赶快去看看Glide的构造方法。这里咱们插入一点很是重要的分析,理解清楚它对接下来的网络执行很是的重要:回到Glidet的构造方法来看看Registry中几个特殊的解析类:

registry.register(xx)
        .append(xx)
        ...
        .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
        ...
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
        ...
        ;

还有印象这段很长的代码吧?

咱们重点来看看上面的两个append方法,其余的都是同样或是相似的道理的。跟进去registry的append方法中:

继续进入modelLoaderRegistry.append方法中:

再跟进multiModelLoaderFactory.append方法中:

重点来了,最后进去add方法:

这里能够看到什么?你理解了吗?

建立了一个Entry对象,把咱们的modelClass,dataClass和factory对象关联起来,而后存放到entries的list集合中,就这么简单,可是对这个Entry对象的理解关系到咱们后面对整个网络加载的流程十分的巨大,ok,到这里,咱们插入的讲解已经完了,主要想告诉你的就是这个entries集合包含了那些对象和建立Entry对象所关联的类和工厂。

那么如今回到DecodeHelper中的getLoadData方法中,它从GlideContext获取到Registry对象,Registry对象有哪些内容在上面的插入讲解中也已举特例分析了,而后调用getModelLoaders方法,并传进model对象,那么来看看它是怎么实现的:

它会从modelLoaderRegistry中获取,在来看:

它会经过model从getModelLoadersForClass方法中获取到modelLoaders的集合,来看看:

首先从cache缓存中获取,若是为空,将会从multiModelLoaderFactory工厂中获取,在继续跟进multiModelLoaderFactory的build方法看看:

从entries集合中分别的遍历出entry对象,而后调用entry.handles来进行匹配是否符合,来看handles方法:

this.modelClass是什么还记得吗?没错就是在Glide建立Registry对象是append的XX.class,例如:

.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())

而modelClass呢,这里就是咱们传递用来加载网络图片的一个url地址,那么调用isAssignableFrom方法进行匹配,咱们知道entries包含不少的解析器,因此在这一步将会排除掉不匹配的解析器,而后调用调用build方法来建立加载器:

entry.factory知道是什么吧?没错就是append方法中new的一个工厂类。

仍是如下面的特例来讲:

.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())

在这里这个factory就是HttpUriLoader.Factory,咱们来看看它是怎么实现的:

这里它将会multiFactory.build方法来构造一个ModelLoader对象,看清楚它传递的参数:GlideUrl.class, InputStream.class,而后跟进去查看:

历史老是惊人的类似,再次从entries中获取Entry对象,而后调用entry.handles方法根据GlideUrl.class, InputStream.class这两个参数进行匹配过滤。

而后咱们找到了如下的append内容相匹配的Entry对象

.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())

找到HttpGlideUrlLoader.Factory以后,而后调用build方法去构建,在build方法中一样的方式调用entry.factory.build(this),来看看HttpGlideUrlLoader.Factory()的build的源码:

直接的建立一个HttpGlideUrlLoader对象并返回。

到此咱们获取了真正的图片加载对象,而后咱们回到HttpUriLoader的Factory中:在multiFactory.build(GlideUrl.class, InputStream.class)获取到HttpGlideUrlLoader对象后,并传递到建立的HttpUriLoader对象中去,咱们来看看:

把HttpGlideUrlLoader对象赋值给HttpUriLoader的成员变量this.urlLoader中。

ok,到此咱们真正的加载器已经获取到了,固然并非只有一个,可能有多个,由于在Registry注册了多个能够解析Uri.class的解析器。

好,咱们在回到ModelLoaderRegistry类中的getModelLoaders方法中,从getModelLoadersForClass方法中咱们获取到了能够解析咱们请求modle的全部解析器,经过for循环遍历出全部的解析器,存放到filteredLoaders集合中并返回,一直返回到DecodeHelper类中的getLoadData方法中。

而后遍历modelLoaders集合,分别获取ModelLoader对象,并调用buildLoadData方法,咱们知道modelLoaders集合中必定会包含一个ModelLoader是HttpUriLoader,那来看看它的buildLoadData方法:

它会调用urlLoader.buildLoadData方法,这个urlLoader就是HttpGlideUrlLoader对象,再来看看:

这里最重要的就是建立个一个HttpUrlFetcher对象:

而后把HttpUrlFetcher对象存放到新建的LoadData对象中:

最后把LoadData对象返回,咱们往上返回到SourceGenerator的startNext方法中:

在获取到LoadData对象后,调用loadData.fetcher.loadData(helper.getPriority(), this);这个方法,从上面分析loadData.fetcher就是HttpUrlFetcher对象,那咱们来看看它里面的loadData是怎么加载数据的:

它会调用loadDataWithRedirects方法来返回一个InputStream输入流,来看看loadDataWithRedirects的源码:

private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map<String, String> headers) throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
      throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
      // Comparing the URLs using .equals performs additional network I/O and is generally broken.
      // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
      try {
        if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
          throw new HttpException("In re-direct loop");

        }
      } catch (URISyntaxException e) {
        // Do nothing, this is best effort.
      }
    }

    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (statusCode / 100 == 2) {
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (statusCode / 100 == 3) {
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == -1) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }

这里的代码咱们就很是的熟悉了,稍微的简单介绍下:

①:connectionFactory对象是在建立HttpUrlFetcher对象时在构造方法中初始化的,它就是DEFAULT_CONNECTION_FACTORY,也就是DefaultHttpUrlConnectionFactory工厂类,当调用它的build方法时:

经过url打开链接,返回一个HttpURLConnection对象,用于网络请求,这些代码日常咱们都有接触,很少说。

②:创建链接,过去返回状态码,判断,而后经过getStreamForSuccessfulRequest方法返回一个InputStream输入流。

在获取到InputStream输入流以后,最会将会调用callback.onDataReady(result);回调方法,并把输入流传递过去。

那这个callback是什么呢?

还记得loadData.fetcher.loadData(helper.getPriority(), this);这段代码吧?

没错他就是SourceGenerator类实现的DataCallback回调类。

那么在进到SourceGenerator找到onDataReady方法吧:

在这里它又调用cb回调类的onDataFetcherReady方法,并传递了相关参数:loadData.fetcher是HttpUrlFetcher,loadData.fetcher.getDataSource()则是DataSource.REMOTE:

@Override
  public DataSource getDataSource() {
    return DataSource.REMOTE;
  }

那么这个cb又是什么呢,它是FetcherReadyCallback回调类,在DecodeJob中实现,那么回到DecodeJob的onDataFetcherReady方法中:

在onDataFetcherReady方法中保存了相关的参数变量,判断是不是当前线程,而后调用decodeFromRetrievedData方法来解码数据:

首先建立一个Resource类型的变量,经过decodeFromData方法把输入流解码并返回给resource,由此可也看出,解码主要是在decodeFromData方法中:

在这里已经体现loadData.fetcher这个fetcher的用意,主要是去关闭输入流和HttpUrlConnection的。

@Override
  public void cleanup() {
    if (stream != null) {
      try {
        stream.close();
      } catch (IOException e) {
        // Ignore
      }
    }
    if (urlConnection != null) {
      urlConnection.disconnect();
    }
  }

在这以前它又调用decodeFromFetcher方法来进行解码返回一个Resource:

在这里获取到data.getClass,这个Class就是InputStrem.class,那么在调用decodeHelper.getLoadPath方法后,咱们来看看作了哪些操做:

getLoadPath方法啥也没作,直接调用Registry中的getLoadPath,并传递了拥有的变量,其中resourceClass是Object.class,transcodeClass则是Drawable.class,这是在前面已构建初始化好的,直接拿来用。

咱们在来跟进去看看

这里首先从loadPathCache缓存中获取LoadPath对象,若是没有则调用getDecodePaths方法进行获取:

getDecodePaths方法中仍是蛮重要的,对真个解码过程的理解有很大的帮助,因此咱们来认真的分析下:

①:首先从decoderRegistry.getResourceClasses方法中获取已经注册的registeredResourceClasses:

还记得咱们建立Registry是注册了一大堆的东西吗?

对,经过handles方法对InputStrem.class和Object.class进行匹配的就是咱们用红色框画出来的部分。由此咱们能够得出registeredResourceClasses集合中分别对应的是Bitmap.class,BitmapDrawable.class和GifDrawable.class的三种Class对象。

②:遍历registeredResourceClasses集合,经过transcoderRegistry.getTranscodeClasses方法获取到已注册的registeredTranscodeClasses集合:

这是对registeredResourceClasses集合的再次匹配,咱们知道transcodeClasses其实是Drawable.class,在registeredResourceClasses集合中只有BitmapDrawable.class和GifDrawable.class是继承Drawable的,由此咱们得出registeredTranscodeClasses包含BitmapDrawable.class和GifDrawable.class两种Class对象。

那么由此可知decoders存放了两种解码器:

对应的BitmapDrawable的BitmapDrawableDecoder解码器。
对应的GifDrawable.class的StreamGifDecoder解码器。

这个很是重要,在后面有使用到。必须理解清楚。

③:经过上面获取的registeredResourceClass和registeredTranscodeClass获取到transcoder转化器,主要是从transcoderRegistry集合中经过get方法获取,而transcoderRegistry又包含哪些转化器呢?

而又有get方法咱们能够知道:

当时普通图片是transcoder将会是BitmapDrawableTranscoder,如是过动态图片gif的话transcoder将会是GifDrawableBytesTranscoder。

而后把它们存放到建立的DecodePath对象中:

最后是把封装好的DecodePath对象存储到decodePaths集合中并返回。

而后在回到Registry中的getLoadPath方法中,在获取到decodePaths集合中,把它和dataClass, resourceClass, transcodeClass又封装到LoadPath对象中,并缓存到loadPathCache对象中。

再次返回DecodeJob类中的decodeFromFetcher方法中,在获取到LoadPath后,调用runLoadPath方法,来看下它的源码:

它调用glideContext.getRegistry()获取Registry对象,而后调用Registry的getRewinder获取装置器,跟进去看看:

在getRewinder方法中直接的调用dataRewinderRegistry对象的build方法,那么这个dataRewinderRegistry又是什么呢?

它是在Registry构造方法中建立的对象:

this.dataRewinderRegistry = new DataRewinderRegistry();

并且在Glide中进行了注册:

获取到factory以后调用dataRewinderRegistry.register方法注册到Map集合rewinders中去:

再来看看factory.getDataClass()都获取到哪些key:

①:在ByteBufferRewinder.Factory中调用getDataClass()获取的key是ByteBuffer.class

②:在InputStreamRewinder.Factory中调用getDataClass()获取的key是InputStream.class

上面两个key值在接下来会使用到。

那么咱们在返回到getRewinder方法中,调用dataRewinderRegistry对象的build方法到底作了什么:

在build的方法中总共作了四件事,分别用不一样的线框标注出来了:

①:从rewinders集合中获取到和data.getClass()相匹配的Factory对象,从上面的分析中,咱们知道rewinders注册的只有两个key,分别是ByteBuffer.class和InputStream.class,而咱们又知道data.getClass()是一个InputStream.class,由此能够匹配成功。这个result就是InputStreamRewinder.Factory对象。

②:假如result没有匹配成功的话,也就是没有经过key匹配成功,那么就进行遍历rewinders集合,经过values值进行匹配,把匹配成功的Factory对象再赋值给result。

③:假如经过键key和值values都没有匹配成功,那么也没关系,直接使用默认的DEFAULT_FACTORY

④:最后调用result的build方法。

这里因为咱们经过键key直接已匹配成功,因此咱们知道result就是InputStreamRewinder.Factory对象,那么来看看调用它的build方法作了什么事情:

这里直接的返回了一个InputStreamRewinder对象,在InputStreamRewinder的构造方法中又建立了RecyclableBufferedInputStream对象,并它InputStream流传递进去:

RecyclableBufferedInputStream继承FilterInputStream流,那么咱们的InputStream流最终保存的位置就是在FilterInputStream类中。

ok,到这里咱们知道了InputStream数据流的去向,而在InputStreamRewinder中又有对InputStream流的引用,那么在回到InputStreamRewinder以后咱们来看看接下来又作了什么呢?

再次定位到DecodeJob类中的runLoadPath方法,在获取到InputStreamRewinder后,它会调用path.load方法并返回Resource资源类,这个path是在以前获取到的LoadPath对象,这里注意下,传递了一个new DecodeCallback 对象的回调类,后面会用到。最后调用InputStreamRewinder.cleanup()进行资源释放。那么咱们来看看LoadPath的load方法是怎么实现的:

它直接调用loadWithExceptionList方法进行移交:

在loadWithExceptionList方法中则会调用decode方法进行解码:

decode方法中调用decodeResource方法,而后在调用decodeResourceWithList方法真正的开始解码:

①:这里首先遍历decoders集合,分别的获取到ResourceDecoder解码器,还记得咱们的decoders都包含哪些解码器吗?没错主要包含两种:BitmapDrawable.class和GifDrawable.class。不记得的往上面翻下,上面已详细的讲解过了。

②:而后经过rewinder.rewindAndGet()获取咱们的InputStream数据流:

③:经过decoder.handles(data, options)方法来过滤掉不相匹配的解码器,再来看看前面的这张图:

Bitmap.class已被咱们过滤掉,剩下的就只有BitmapDrawable.class和GifDrawable.class,当咱们调用handles方法进行匹配时,StreamGifDecoder解码器是怎么处理的:

它主要是针对options属性为gif的图片来解码的,其实这不用我说你们也是知道的,而咱们加载的只是普通的静态图片,所以它是不符合咱们的匹配规则的,在来看BitmapDrawableDecoder中,它传入的是StreamBitmapDecoder的解码器:

而downsampler.handles(source);中只要source是InputStream就返回true,所以匹配成功。

那么由上分析,咱们真正的decoder就是BitmapDrawableDecoder。

回到decodeResourceWithList方法中,获取到真正的decoder解码器,将会调用decode方法正式解码:

它又会交给StreamBitmapDecoder的decode方法,而后在转移到Downsampler类中的decode方法中:

这里就再也不一个一个的看方法了,主要是在Downsampler中decodeFromWrappedStreams方法中把InputStream数据流根据width, height, options给转化成Bitmap图片,而后把Bitmap存放到BitmapResource对象中去且直接的返回自己。

ok,获取到BitmapResource对象后,再次返回最初开始解码的DecodePath类中的decode方法中:

从上面分析咱们知道,咱们解析的是普通的图片,因此这个transcoder就是BitmapDrawableTranscoder转换器类。(前面有详细的分析,忘记的能够向上翻看)

接着咱们去BitmapDrawableTranscoder中的transcode方法看看:

在transcode方法中经过toTranscode.get()获取bitmap图片,这个bitmap虽然通过多层的包装,它其实就是一个BitmapResource对象,这在上面咱们有清楚的分析,只不过在返回的回调方法中有屡次的封装而已。

获取到Bitmap图片后,调用LazyBitmapDrawableResource的obtain方法再次进行一次的封装:

把Bitmap封装到LazyBitmapDrawableResource对象中进行返回。

ok,到这里其实已完成了完彻底全的解码和封装到。

一路把LazyBitmapDrawableResource对象返回到DecodeJob类中的decodeFromRetrievedData中,并赋值给resource变量:

当resource不为空时,将会调用notifyEncodeAndRelease方法并传递参数:

方法里面就很少解析了,它会调用notifyComplete方法:

这里调用了callback.onResourceReady(resource, dataSource);方法,那这个callback是什么呢?它实际上是一个ResourceCallback,在SingleRequest中发起的,而且SingleRequest还实现了ResourceCallback接口内的方法:

public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    loadStatus = null;
    if (resource == null) {
      GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
          + "object of " + transcodeClass + " inside, but instead got null.");
      onLoadFailed(exception);
      return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      releaseResource(resource);
      GlideException exception = new GlideException("Expected to receive an object of "
          + transcodeClass + " but instead" + " got "
          + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " "
          + "Resource{" + resource + "}."
          + (received != null ? "" : " " + "To indicate failure return a null Resource "
          + "object, rather than a Resource object containing null data."));
      onLoadFailed(exception);
      return;
    }

    if (!canSetResource()) {
      releaseResource(resource);
      // We can't put the status to complete before asking canSetResource().
      status = Status.COMPLETE;
      return;
    }

    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

重点讲解下:在onResourceReady中使用resource.get(),咱们知道这个resource就是LazyBitmapDrawableResource对象,来看看这个get获取到了什么:

在get中获取到了BitmapDrawable对象直接复制给了received变量,而后调用重载方法onResourceReady方法:

在onResourceReady方法中调用了target.onResourceReady(result, animation);还记得target是什么吗?

它在load方法中已讲解过,就是DrawableImageViewTarget对象,调用它的onResourceReady会转移到父类ImageViewTarget中:

而后在调用setResourceInternal方法:

setResource是抽象方法,由它的子类实现,咱们在回到DrawableImageViewTarget中:

到这里直接调用view进行设置图片了,这个view就是咱们Imageview了,因此到这里就设置好了加载的图片了。

ok,到这里就完彻底全的解析完了Glide的执行原理了。

说实在的Glide的源码很是的复杂,每每深刻进去就没法出来了,相信这篇博客很能好的给你们一个参考,能让你们对整个Glide有个全面的理解。

好了,终于写完了,真的很不容易,很辛苦,但愿你们也能从中学到知识。

各位若是还有哪里不明白的,或是我这里讲的还不够透彻,亦或是讲错了的地方请留言指正,让咱们共同进步,谢谢

同时,请你们扫一扫关注个人微信公众号,虽然写的不是很勤,可是每一篇都有质量保证,让您学习到真正的知识。

请关注个人微信公众号

相关文章
相关标签/搜索