Glide笔记----加载网络图片

  Glide是一个图片加载框架,使用方法如下:

  添加依赖:

    implementation "com.github.bumptech.glide:glide:$glide_version"
    annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"

  Glide版本号参考Glide地址:https://github.com/bumptech/glide

  使用方式如下:

//图片的URL
var imageUrl = "xxxxxxx"
Glide.with(this).load(imageUrl).into(dataBinding.imageView)

  本文主旨介绍Glide加载网络图片的流程,不过多介绍Glide的生命周期、图片变换及图片缓存。

  Glide的工作流程

  首先,根据给定的图片URL创建一个图片加载请求(以加载网络图片为例)。然后,在子线程执行图片加载请求,获取图片的输入流,将输入流解析为图片(Bitmap),并对得到的图片进行变换和保存处理。最后,将图片回调至主线程,进行展示。

  Glide加载网络图片的工作流程图如下所示:

  Glide加载图片流程概述

  一、创建图片加载请求

  首先、调用Glide的with方法,此方法会触发Glide的初始化,初始化Glide的各种线程池、图片解码编码器、 图片加载器等。然后、调用load(url)方法,此方法会返回一个RequestBuilder,以构造图片加载请求。Glide采用建造者模式来创建图片加载请求。最后,调用Glide的into(ImageView)方法,此方法首先将ImageView封装到ViewTarget中,ViewTarget可以看作一个回调接口,在图片加载完成后,会将加载到的图片放到ImageView中;然后,构建图片加载请求,并通知请求管理器(ReuqestManager)执行此图片加载请求。

  二、执行图片加载请求

  图片加载请求(Request)构建完成之后,Glide会通知请求管理器去执行此图片加载请求。请求执行过程为:首先,根据图片加载策略(本地或远程加载),获取DataFetcherGenerator,顾名思义,DataFetcherGenerator是用来生成DataFetcher的,而DataFetcher是一个用来获取图片数据的接口。例如,策略为通过网络加载,则得到是SourceGenerator,其为DataFetcherGenerator的子类。然后,DataFetcherGenerator会构造出指定类型的DataFetcher,并使用DataFetcher来加载图片数据。最后,将图片数据交给回调接口。

  以加载网络图片来说明上述过程。若为加载网络图片,则得到的DataFetcher生成器为SourceGenerator。SourceGenerator首先会根据图片的URL(URL在Glide中会变化为model),获取ModelLoader,ModelLoader的目的是将Model转化为图片数据(Data)。然后,Glide通过ModelLoader构造出包含DataFetcher的LoadData,加载网络图片的DataFetcher是HttpUrlFetcher,LoadData则包含了缓存图片时用的key及加载图片的DataFetcher对象。最后,在得到图片输入流后,将其交给回调接口,回调接口的作用是将图片输入流转化为图片,并对图片进行变化和缓存处理。

  在此介绍一下Glide如何通过model获取ModelLoader。Glide在初始化时,会将全部的种类的ModelLoader存储到ModelLoaderRegistry,与ModelLoader一同存储的还有Model和Data的类型。前面也提到过ModelLoader的目的就是将Model转化为Data。这里Model可以看作是URI,Data可以看作是URI对应的资源。比如,加载网络图片时,Model是字符串,其类型是String,Data是图片输入流,其类型是InputStream,ModelLoader则是将图片URL转化为图片输入流。这样,在获取ModelLoader时,Glide会遍历ModelLoaderRegistry中存储的ModelLoader,并检查ModelLoader是否能够处理Model,若能够处理,则将其添加到返回结果集合中。实际上,Glide在初始化时,并没有直接将ModelLoader对象存储到ModelLoader中,而是存储了ModelLoader的构造器,即xxxxxFactory,这样在第一次从ModelLoaderRegistry中读取ModelLoader时,会先调用xxxxFactory的构造方法来构造ModelLoader,然后再将ModelLoader保存到ModelLoaderRegistry中。

  在得到图片数据后,Glide会使用ResourceDecoder将图片数据(Data)转化为图片(Resource)。比如,加载网络图片时,在得到图片的输入流后,会调用BitmapDrawableDecoder的decode方法将输入流转化为BitmapDrawable,BitmapDrawableDecoder为ResourceDecoder的子类。在得到图片之后,Glide会对图片进行变化和缓存处理,本文不对此进行过多介绍。

  三、展示图片

  在加载图片时,Glide首先创建了一个DecodeJob对象(实现了Runnable),运行在子线程以加载、变化及缓存图片。然后,创建了一个EngineJob实现并注册了DecodeJob的回调接口,这样就可以得到处理后的图片,并将图片展示任务通过Handler发送到了主线程。

  接下来,将对上述3个过程进行详细介绍。

一、创建图片加载请求

  1.1、初始化Glide

  Glide在加载图片之前,会先构造图片加载请求,而在构造加载请求之前,通常会先初始Glide框架。例如,在调用Glide的with方法时,会对Glide进行初始化。

Glide.with(this)

  此方法的返回结果为RequestManager,用来创建图片加载请求。此方法最终会调用Glide的get方法,如下所示:

  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          //初始化Glide
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }

    return glide;
  }

  chechAndInitializeGlide方法首先会进行一些检查。然后,调用GlideBuilder的build方法创建一个Glide对象,并将其设置为单实例。build方法代码如下:

    Glide build(@NonNull Context context) {
        if (this.sourceExecutor == null) {
            //创建加载图片的线程
            this.sourceExecutor = GlideExecutor.newSourceExecutor();
        }

        if (this.diskCacheExecutor == null) {
            this.diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
        }
        ......
        if (this.engine == null) {
            this.engine = new Engine(this.memoryCache, this.diskCacheFactory, this.diskCacheExecutor, this.sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor(), this.animationExecutor, this.isActiveResourceRetentionAllowed);
        }
        ......

        GlideExperiments experiments = this.glideExperimentsBuilder.build();
        RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(this.requestManagerFactory, experiments);
        //创建Glide
        return new Glide(context, this.engine, this.memoryCache, this.bitmapPool, this.arrayPool, requestManagerRetriever, this.connectivityMonitorFactory, this.logLevel, this.defaultRequestOptionsFactory, this.defaultTransitionOptions, this.defaultRequestListeners, experiments);
    }

  在此只展示一些和图片加载相关的代码。首先,此方法会创建用于加载网络图片的线程池。然后,创建Glide对象。Glide的此构造方法较长,因此只展示以下部分:输入流转化为Bitmap的解码器、输入流转化为BitmapDrawable的解码器及将URL转化为图片输入流的转化器(ModelLoader)。

Glide(
      @NonNull Context context,
      @NonNull Engine engine,
      @NonNull MemoryCache memoryCache,
      @NonNull BitmapPool bitmapPool,
      @NonNull ArrayPool arrayPool,
      @NonNull RequestManagerRetriever requestManagerRetriever,
      @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
      int logLevel,
      @NonNull RequestOptionsFactory defaultRequestOptionsFactory,
      @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
      @NonNull List<RequestListener<Object>> defaultRequestListeners,
      GlideExperiments experiments) {
    this.engine = engine;
    this.bitmapPool = bitmapPool;
    this.arrayPool = arrayPool;
    this.memoryCache = memoryCache;
    this.requestManagerRetriever = requestManagerRetriever;
    this.connectivityMonitorFactory = connectivityMonitorFactory;
    this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;

    final Resources resources = context.getResources();

    registry = new Registry();
    ......


    // TODO(judds): Make ParcelFileDescriptorBitmapDecoder work with ImageDecoder.
    Downsampler downsampler =
        new Downsampler(
            registry.getImageHeaderParsers(), resources.getDisplayMetrics(), bitmapPool, arrayPool);

    ResourceDecoder<ByteBuffer, Bitmap> byteBufferBitmapDecoder;
    ResourceDecoder<InputStream, Bitmap> streamBitmapDecoder;
    if (experiments.isEnabled(EnableImageDecoderForBitmaps.class)
        && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
      //创建将数据流转化为Bitmap的解码器
      streamBitmapDecoder = new InputStreamBitmapImageDecoderResourceDecoder();
      byteBufferBitmapDecoder = new ByteBufferBitmapImageDecoderResourceDecoder();
    } else {
      byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
      streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
    }
    ......

    registry
        .append(ByteBuffer.class, new ByteBufferEncoder())
        .append(InputStream.class, new StreamEncoder(arrayPool))
        /* Bitmaps */
        .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
        //保存 “将数据流转为Bitmap”的解码器
        .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder);

        ......

    registry
        .append(
            Registry.BUCKET_BITMAP,
            ParcelFileDescriptor.class,
            Bitmap.class,
            parcelFileDescriptorVideoDecoder)
        ......
        /* BitmapDrawables */
        .append(
            Registry.BUCKET_BITMAP_DRAWABLE,
            ByteBuffer.class,
            BitmapDrawable.class,
            new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
        //保存“将数据流转化为BitmapDrawable”的解码器
        .append(
            Registry.BUCKET_BITMAP_DRAWABLE,
            InputStream.class,
            BitmapDrawable.class,
            new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
        .......

    if (ParcelFileDescriptorRewinder.isSupported()) {
      registry.register(new ParcelFileDescriptorRewinder.Factory());
    }

    registry
        .append(int.class, InputStream.class, resourceLoaderStreamFactory)
        .......
        .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
        .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
        //添加StringLoader(ModelLoader的子类)的构建者,StringLoader可以将String类的Model
        //转化为InputStream类型的Data
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        ......

    registry
        .append(Uri.class, InputStream.class, new UriLoader.StreamFactory(contentResolver))
        ......
        //添加UrlUriLoader的构建者,可以看出其会将Uri类的Model转化为InputStream类的Data
        .append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
        .append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
        .append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
        //添加HttpGlideUrlLoader的构建者,HttpGlideUrlLoader负责将图片的GlideUrl
        //转为图片输入流。上面介绍的几类ModelLoader最终都会将获取图片输入流的任务委托
        //给HttpGlideUrlLoader
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
        ......


    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptionsFactory,
            defaultTransitionOptions,
            defaultRequestListeners,
            engine,
            experiments,
            logLevel);
  }

  1.2、创建图片加载请求

  在Glide初始化结束后,接下来就要创建图片加载请求。Glide采用建造者模式来创建图片加载请求(Request)。图片加载请求的创建主要分为2步,首先,创建请求构造者(RequestBuilder),若有图片变化需求,则可以对RequestBuilder进行配置(调用centerCrop等方法)。然后,RequestBuilder根据给定的配置构建图片加载请求(SingleRequestt)。

  1)创建ReuqestBuilder

  Glide的load方法会创建一个ReuqestBuilder,代码如下:

public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
        return this.asDrawable().load(drawable);
    }

    @NonNull
    @CheckResult
    //根据之前的例子,会调用此load方法
    public RequestBuilder<Drawable> load(@Nullable String string) {
        return this.asDrawable().load(string);
    }

    @NonNull
    @CheckResult
    public RequestBuilder<Drawable> load(@Nullable Uri uri) {
        return this.asDrawable().load(uri);
    }

    @NonNull
    @CheckResult
    public RequestBuilder<Drawable> load(@Nullable File file) {
        return this.asDrawable().load(file);
    }

    @NonNull
    @CheckResult
    public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
        return this.asDrawable().load(resourceId);
    }

  Glide中存在多个重载的load方法,以实现多态性。根据上面的例子,最终会调用参数为String类型的load方法。接着,调用asDrawable方法,代码如下:

    public RequestBuilder<Drawable> asDrawable() {
        return this.as(Drawable.class);
    }

  此方法会去调用as方法,并闯入Drawable.class。as方法代码如下:

    public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder(this.glide, this, resourceClass, this.context);
    }

  可以看出as方法会创建一个ReuqestBuilder,这里resourceClass的类型时Drawable.class,表示最终需要得到一个Drawable类型的图片。

  2)、创建图片加载请求Request

  当调用Glide的into方法时,会创建一个Request,代码如下:

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    ......

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

  此方法首先,将ImageView封装到ViewTarget中。然后,去调用了另一个重载的into方法,这里注意最后一个参数为主线程的线程池,意味着在图片加载完成后,会将得到的图片放到此主线程池中处理。重载的into方法代码如下:

 private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    //创建Reuqest
    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    ......

    requestManager.clear(target);
    target.setRequest(request);
    //执行Request,加载图片
    requestManager.track(target, request);

    return target;
  }

  可以看出此方法首先会,调用buildRequest方法来构建Request。然后,调用RequestManager的track方法去执行Request,加载图片。这里先给出track方法代码:

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

  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      //执行Request
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

  在此会调用Request的begin方法来执行Request,而Request是一个接口,具体的Request实例由buildRequest方法返回。buildRequest方法代码如下:

  private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    return buildRequestRecursive(
        /*requestLock=*/ new Object(),
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }

  接着调用buildRequestRecursive方法,代码如下:

private Request buildRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {

    ......

    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);
    ......
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

private Request buildThumbnailRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    if (thumbnailBuilder != null) {
      ......
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      ......

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      //调用此方法
      return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    }
  }

  接下来,会调用obtainRequest方法,代码如下:

private Request obtainRequest(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      Executor callbackExecutor) {
    return SingleRequest.obtain(
        context,
        glideContext,
        requestLock,
        model,  //图片的URL
        transcodeClass,  //Drawable.class
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,  //之前封装的ViewTarget
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);//主线程池
  }

  可以看到,最终构建了一个SingleRequest实例,来表示图片加载请求。

二、执行图片加载请求 

  2.1、进行网络请求,获取图片的数据流

  在上节简单提过,在得到Request后,会调用Request的begin方法来执行图片加载。针对加载网络图片,得到Request为SingleRequest,其begin方法代码如下:

public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      if (model == null) {
        ......
        return;
      }

      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }

      
      if (status == Status.COMPLETE) {
        onResourceReady(
            resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
        return;
      }

      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        //调用此方法
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        target.getSize(this);
      }
      ......
    }
  }

  接着会调用onSizeReady方法,其代码如下:

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      ......
      status = Status.RUNNING;

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

      ......
      loadStatus =
          engine.load(
              glideContext,
              model,
              requestOptions.getSignature(),
              this.width,
              this.height,
              requestOptions.getResourceClass(),
              transcodeClass,
              priority,
              requestOptions.getDiskCacheStrategy(),
              requestOptions.getTransformations(),
              requestOptions.isTransformationRequired(),
              requestOptions.isScaleOnlyOrNoTransform(),
              requestOptions.getOptions(),
              requestOptions.isMemoryCacheable(),
              requestOptions.getUseUnlimitedSourceGeneratorsPool(),
              requestOptions.getUseAnimationPool(),
              requestOptions.getOnlyRetrieveFromCache(),
              this,
              callbackExecutor);

      ......
    }
  }

  接下来回调用Engine的load方法,代码如下:

public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,  //Obect.class
      Class<R> transcodeClass, //Drawable.class
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,  //true
      boolean useUnlimitedSourceExecutorPool,  //false
      boolean useAnimationPool,  //false
      boolean onlyRetrieveFromCache,  //false  上述值可以通过Debug模式看到
      ResourceCallback cb,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

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

    EngineResource<?> memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }

  waitForExistingOrStartNewJob方法代码如下:

private <R> LoadStatus waitForExistingOrStartNewJob(
      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,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      Executor callbackExecutor,
      EngineKey key,
      long startTime) {

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

    //负责将处理好的图片发送到主线程
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
    //负责对图片进行变化和缓存处理
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);
    //将engineJon注册为回调接口,当decodeJob完成工作时,会通知engineJob将图片发到主线程处理
    jobs.put(key, engineJob);
    //callbackExecutor即主线程池
    engineJob.addCallback(cb, callbackExecutor);
    //开始加载图片
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

  在此会通过engineJob的start方法启动图片加载任务,start方法代码如下:

  public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

  可以看到,此方法会选择一个线程池去执行decodeJob,因为是从网络获取图片,所以executor从getActiveSourceExecutor()方法中获取,其代码为:

  private GlideExecutor getActiveSourceExecutor() {
    //这几个变量是从engine.load方法传入的,前面已经说明了这几个变量的值
    //综合分析,返回值为sourceExecutor,这个线程池在Glide初始化时会被初始化,之前已简单介绍
    return useUnlimitedSourceGeneratorPool
        ? sourceUnlimitedExecutor
        : (useAnimationPool ? animationExecutor : sourceExecutor);
  }

  接下来decodeJob会在sourceExecutor线程池中运行,以加载并处理图片,具体运行代码如下:

  public void run() {
    
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (CallbackException e) {
      // If a callback not controlled by Glide throws an exception, we should avoid the Glide
      // specific debug logic below.
      throw e;
    } catch (Throwable t) {
      ......
    }
  }

  runWrapped方法代码如下:

  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        //获取DataFetcher生成器
        currentGenerator = getNextGenerator();
        //加载网络图片并处理
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

  此方法首先会调用getNextGenerator方法,其代码如下:

  private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        //因为是从网络加载图片,所以返回SourceGenerator
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

  接下来,会调用runGenerators方法,代码如下:

  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    ......
  }

  在此方法中,会调用sourceGenerator的startNext方法来加载图片,代码如下:

  public boolean startNext() {
    ......
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      //获取LoadData,前面介绍过了,LoadData中包含了可以获取图片数据的DataFetcher
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        //获取图片数据
        startNextLoad(loadData);
      }
    }
    return started;
  }

  此方法首先,寻找能够加载图片的loadData,可能会得到多个种类的LoadData。然后,调用startNextLoad方法,并将得到的loadData传入,以尝试使用这多个LoadData去加载图片,直至图片加载成功。

  1)、查找loadData(getLoadData()方法)

  此过程的大概流程为:首先,根据Model(即之前传入的图片URL),找出可以处理此Model的一组ModelLoader。然后,调用ModelLoader的buildLoadData方法构造LoadData。最后,就可以得到一组LoadData了。注意:在调用ModelLoader的buildLoadData方法构造LoadData时,存在一些委派构造的情况,即有些ModelLoader会委派其他ModelLoader去构造LoadData,而非直接构造LoadData。在委派构造时,ModelLoader并没有直接持有受委派的ModelLoader的引用,而是使用了一个MultiModelLoaderFactory类的全局实例,通过调用其build方法,并传不同的参数,以构造出不同的LoadData。

  接下来,通过代码进行解释。getLoadData方法代码如下:

  List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      //根据Model,获取能够转化Model的ModelLoader
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //遍历得到的ModelLoader,并用其构造LoadData
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }

  getModelLoader方法代码如下:

  public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
    return modelLoaderRegistry.getModelLoaders(model);
  }
  public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {

    //根据Model类型,获取可以处理此Model类型的ModelLoader
    //如Model的类型为String,则返回的可能包含以下ModelLoader:
    //DataUrlLoader、StringLoader等
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    if (modelLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model);
    }
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();

    //对上述获取的ModelLoader进行过滤。
    //例如,model为图片URL,则会将DataUrlLoader过滤掉,只保留StringLoader
    for (int i = 0; i < size; i++) {
      ModelLoader<A, ?> loader = modelLoaders.get(i);

      //检查ModelLoader是否能够真正处理model
      if (loader.handles(model)) {
        if (isEmpty) {
          filteredLoaders = new ArrayList<>(size - i);
          isEmpty = false;
        }
        filteredLoaders.add(loader);
      }
    }
    if (filteredLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model, modelLoaders);
    }
    return filteredLoaders;
  }

  此方法首先,调用getModelLoadersForClass方法,以获取可以处理Model类型的ModelLoader。然后,对ModelLoader进行过滤,以保留真正可以处理Model的ModelLoader。getModelLoadersForClass方法代码如下:

  private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
      @NonNull Class<A> modelClass) {
    List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
    if (loaders == null) {
      //build方法代码如下
      loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
      cache.put(modelClass, loaders);
    }
    return loaders;
  }
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
    try {
      List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
      //Entry中包含了3部分信息,分别是Model、Data以及ModelLoaderFacotry
      //entries中的这些信息,其实在Glide初始化就进行了保存,详见上一节“Glide初始化”
      for (Entry<?, ?> entry : entries) {
        //避免方法递归时栈溢出
        if (alreadyUsedEntries.contains(entry)) {
          continue;
        }
        //过滤能够处理Model的Entry,并使用Entry中的ModelLoaderFactory构造ModelLoader
        if (entry.handles(modelClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Object>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      return loaders;
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

  这样就得到了一组可以处理Model的ModelLoader,接下来调用ModelLoader的buildLoadData方法来构建LoadData。结合Model的类型(即String)与Glide初始化时添加的ModelLoader构造器,通过分析可知,与加载网络图片相关的ModelLoader时StringLoader,所以下面只展示StringLoader的buildLoadData方法:

public class StringLoader<Data> implements ModelLoader<String, Data> {
  private final ModelLoader<Uri, Data> uriLoader;

  // Public API.
  @SuppressWarnings("WeakerAccess")
  public StringLoader(ModelLoader<Uri, Data> uriLoader) {
    this.uriLoader = uriLoader;
  }

  @Override
  public LoadData<Data> buildLoadData(
      @NonNull String model, int width, int height, @NonNull Options options) {
    //将字符串解析为Uri
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
  }
  ......
}

  可以看到这里调用了UriLoader的buildLoadData方法,以构造一个LoadData。这就是前面说的委派构造。uriLoader是在构造StringLoader时传入的,所以看下StringFactory如何构造StringLoader,构造代码如下:

 public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {

    @NonNull
    @Override
    public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
      //通过multifacotry的build方法构建了一个ModelLoader,注意这里的Model类型发生了变化
      //由String类型变为了Uri类型
      return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
    }

    @Override
    public void teardown() {
      // Do nothing.
    }
  }

  接下来看下MultiModelLoaderFactory的build方法,代码如下:

public synchronized <Model, Data> ModelLoader<Model, Data> build(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    try {
      List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
      boolean ignoredAnyEntries = false;

      //entries中的数据,在Glide初始化时被赋值
      for (Entry<?, ?> entry : entries) {
        if (alreadyUsedEntries.contains(entry)) {
          ignoredAnyEntries = true;
          continue;
        }
        if (entry.handles(modelClass, dataClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Data>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      if (loaders.size() > 1) {

        //可以获取一组能够将Uri转化为InputStream的ModeLoader(详见Glide初始化),我们主要关注UrlUriLoader
        //因此将这些ModelLoader封装到MultiModelLoader中
        //此build方法代码如下
        return factory.build(loaders, throwableListPool);
      } else if (loaders.size() == 1) {
        return loaders.get(0);
      } else {
        ......
      }
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

  static class Factory {
    @NonNull
    public <Model, Data> MultiModelLoader<Model, Data> build(
        @NonNull List<ModelLoader<Model, Data>> modelLoaders,
        @NonNull Pool<List<Throwable>> throwableListPool) {
      return new MultiModelLoader<>(modelLoaders, throwableListPool);
    }
  }

  可以看出,最终会调用此MultiModelLoader类的buildLoadData方法,其代码如下:

  public LoadData<Data> buildLoadData(
      @NonNull Model model, int width, int height, @NonNull Options options) {
    Key sourceKey = null;
    int size = modelLoaders.size();
    List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
      
      //使用model对得到的ModelLoader进行过滤,在本文分析的情况中,最终只有
      //UrlUriLoader通过过滤(因为model是一个图片的URL)
      if (modelLoader.handles(model)) {

        //调用UrlUriLoader的buildLoadData(委派形式)
        LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
        if (loadData != null) {
          sourceKey = loadData.sourceKey;
          fetchers.add(loadData.fetcher);
        }
      }
    }
    return !fetchers.isEmpty() && sourceKey != null
        ? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool))
        : null;
  }

  可以看出此方法首先,对得到的ModelLoader进行了过滤,经过分析,发现只有UrlUriLoader通过过滤。然后,调用了UrlUriLoader的buildLoadData方法,以生成LoadData,此方法代码如下:

  public LoadData<Data> buildLoadData(
      @NonNull Uri uri, int width, int height, @NonNull Options options) {
    GlideUrl glideUrl = new GlideUrl(uri.toString());
    return urlLoader.buildLoadData(glideUrl, width, height, options);
  }

  可以看出,此方法也是采用委派构造的形式,其委派过程与上述过程相似,因此不再赘述。在此,直接给出最终的LoadData,如下所示:

  public LoadData<InputStream> buildLoadData(
    ......
    int timeout = options.get(TIMEOUT);
    //最终的LoadData
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }

  可以看出,在加载网络图片时,LoadData是使用HttpUrlFetcher来加载图片数据的。

  2)、加载网络图片(startNextLoad()方法)

  在得到loadData之后,可以调用startNextLoad方法加载图片数据,此方法代码如下:

  private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }

          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  }

  可以看到,此方法使用loadData中的fetcher(DataFetcher)来加载图片,根据前面的分析可知,此fetcher的类型为HttpUrlFetcher,其loadData方法代码如下:

  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      //获取图片的输入流
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      //通过回调处理图片输入流
      callback.onDataReady(result);
    } catch (IOException e) {
      ......
    } finally {
      ......
    }
  }

  此方法会调用loadDataWithRedirects方法去获取图片的输入流,最终会通过HttpURLConnetion来获取图片的输入流。在此,本文就不再继续往下分析图片的网络传输过程。在得到图片输入流之后,Glide会使用之前注册的回调接口(DataCallback)进行处理。

  2.2、将数据流转化为图片(Bitmap)

  在得到图片输入流之后,会通过回调接口DataCallback,将输入流交给DecodeJob处理。DataCallback代码如下:

private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          ......
        });
  }

  void onDataReadyInternal(LoadData<?> loadData, Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      cb.reschedule();
    } else {
      //回调decodeJob的方法
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }

  onDataFetcherReady方法的代码如下:

  public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);

    if (Thread.currentThread() != currentThread) {
      ......
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        //对图片输入流进行解码
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

  decodeFromRetrivedData方法代码如下:

  private void decodeFromRetrievedData() {
    ......
    Resource<R> resource = null;
    try {
      //将输入流解码为BitmapDrawable
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      //通知主线程处理得到的BitmapDrawable
      notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
    } else {
      runGenerators();
    }
  }

  decodeFromData方法的目的是解码图片,最终会调用decodeFromFetcher方法,其代码如下:

  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    //获取可以将输入流解码为BitmapDrawable的解码器
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    //将输入流解码为BitmapDrawable
    return runLoadPath(data, dataSource, path);
  }

  上述代码做了2件事,一是根据data的类型,获取可以将data解码为图片的解码器,经过前面的分析,可知这里的data类型为InputStream。二是使用图片解码器,解码data。

  1)、获取图片解码器

  获取图片解码器的大体过程为:首先,根据data的类型和最终图片的类型(Drawable),找出能够处理此data的解码器。然后,将此解码器封装到DecodePath中。最后,将DecodePath封装到LoadPath中,并将LoadPath返回。

  接下来通过代码解释上述过程。getLoadPath方法的代码如下:

  <Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
    //dataClass的类型为InputStream,resourceClass为Object,transcodeClass为Drawable
    return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
  }

  接下来会调用Registry的getLoadPath方法,代码如下:

public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
      @NonNull Class<Data> dataClass,
      @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
    LoadPath<Data, TResource, Transcode> result =
        loadPathCache.get(dataClass, resourceClass, transcodeClass);
    if (loadPathCache.isEmptyLoadPath(result)) {
      return null;
    } else if (result == null) {

      //获取包含解码器的DecodePaths
      List<DecodePath<Data, TResource, Transcode>> decodePaths =
          getDecodePaths(dataClass, resourceClass, transcodeClass);

      if (decodePaths.isEmpty()) {
        result = null;
      } else {
        //将得到的DecodePath封装到LoadPath中
        result =
            new LoadPath<>(
                dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
      }
      loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
    }
    return result;
  }

  getDecodePaths方法的代码如下:

private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
      @NonNull Class<Data> dataClass,
      @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
    List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();

    //此方法返回 可以处理data类型的解码器的处理结果的类型
    //根据Glide初始化时的信息可知,返回值包含以下类型:
    //BitmapDrawable,GifDrawable
    List<Class<TResource>> registeredResourceClasses =
        decoderRegistry.getResourceClasses(dataClass, resourceClass);

    for (Class<TResource> registeredResourceClass : registeredResourceClasses) {

      //若transcodeClass是registeredResourceClass的父类,则直接返回transcodeClass
      //否则,根据Glide初始化时的信息可知,返回的是一个空List
      //在此只有BitmapDrawable,会返回一个只包含Drawable的List。GifDrawable返回空List
      List<Class<Transcode>> registeredTranscodeClasses =
          transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);

      for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {

        //获取可以将InputStream解码为BitmapDrawable的解码器
        //解码器类型为InputStreamBitmapImageDecoderResourceDecoder,其在Glide初始化时被注册
        List<ResourceDecoder<Data, TResource>> decoders =
            decoderRegistry.getDecoders(dataClass, registeredResourceClass);
        ResourceTranscoder<TResource, Transcode> transcoder =
            transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
        @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
        //将解码器封装到DecodePath中
        DecodePath<Data, TResource, Transcode> path =
            new DecodePath<>(
                dataClass,
                registeredResourceClass,
                registeredTranscodeClass,
                decoders,
                transcoder,
                throwableListPool);
        decodePaths.add(path);
      }
    }
    return decodePaths;
  }

  2)、使用图片解码器对输入流进行解码

  在得到图片解码器之后,就可以调用runLoadPath方法对图片进行解码,此方法代码如下:

  private <Data, ResourceType> Resource<R> runLoadPath(
      Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
      throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    //DataRewinder可能会对原始data进行处理,然后返回处理过的data,但是经过分析发现,
    //此处的rewinder直接将原始data返回,并没有进行处理
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }

  接下来会调用LoadPath的load方法解码图片输入流,此方法最后会调用DecodePath的decode方法,如下图所示:

  public Resource<Transcode> decode(
      DataRewinder<DataType> rewinder,
      int width,
      int height,
      @NonNull Options options,
      DecodeCallback<ResourceType> callback)
      throws GlideException {
    //将输入流解码为图片(BitmapDrawable)
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    //对图片进行变换和缓存处理
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }

  可以看出,接下来会调用decodeResource方法对图片输入流进行解码,此方法代码如下:

  private Resource<ResourceType> decodeResource(
      DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options)
      throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

  接着decodeREsourceWithList方法,此方法代码如下:

private Resource<ResourceType> decodeResourceWithList(
      DataRewinder<DataType> rewinder,
      int width,
      int height,
      @NonNull Options options,
      List<Throwable> exceptions)
      throws GlideException {
    Resource<ResourceType> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {

          //从rewinder中读取图片输入流data。rewinder前面已经简单介绍
          data = rewinder.rewindAndGet();
          
          //调用图片解码器将data转化为图片(BitmapDrawable)
          result = decoder.decode(data, width, height, options);
        }
        // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but
        // instead log and continue. See #2406 for an example.
      } catch (IOException | RuntimeException | OutOfMemoryError e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          Log.v(TAG, "Failed to decode data for " + decoder, e);
        }
        exceptions.add(e);
      }
      ......
    }
    ......
    return result;
  }

  此方法最终会调用InputStreamBitmapImageDecoderResourceDecoder的decode方法,对图片输入流进行解码,在此不再继续分析解码过程。

  2.3、对图片进行变换及缓存处理

  在将图片输入流解码为图片之后,调用DecodeJob(其实现了DecodeCallBack)的onResourceDecoded方法对图片进行变换和缓存处理。方法代码如下所示:

<Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      //图片变换处理
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    // TODO: Make this the responsibility of the Transformation.
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }

    ......

    Resource<Z> result = transformed;
    boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
    if (diskCacheStrategy.isResourceCacheable(
        isFromAlternateCacheKey, dataSource, encodeStrategy)) {
      if (encoder == null) {
        throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
      }
      final Key key;
      switch (encodeStrategy) {
        case SOURCE:
          key = new DataCacheKey(currentSourceKey, signature);
          break;
        case TRANSFORMED:
          key =
              new ResourceCacheKey(
                  decodeHelper.getArrayPool(),
                  currentSourceKey,
                  signature,
                  width,
                  height,
                  appliedTransformation,
                  resourceSubClass,
                  options);
          break;
        default:
          throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
      }

      LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
      //图片缓存处理(目前只是将图片记录下来,后面会进行保存)
      deferredEncodeManager.init(key, encoder, lockedResult);
      result = lockedResult;
    }
    return result;
  }

三、将图片回调至主线程并展示

  3.1、图片回调至主线程

  在DecodeJob完成对图片的处理之后,会调用notifyEncodeAndRelease方法,其代码如下:

  private void notifyEncodeAndRelease(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }

    ......

    notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        //保存处理后的图片
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }
    ......
  }

  notifyComplete方法代码如下:

  private void notifyComplete(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    setNotifiedOrThrow();
    //EngineJob实现了DecodeJob.Callback,并在之前进行了注册,
    //所以会调用EngineJob的onResourceReady方法
    callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
  }

  EngineJob的onResourceReady方法代码如下:

  public void onResourceReady(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    synchronized (this) {
      this.resource = resource;  //resource中有加载到的图片
      this.dataSource = dataSource;
      this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
    }
    //此方法如下
    notifyCallbacksOfResult();
  }

  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
        resource.recycle();
        release();
        return;
      } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
      } else if (hasResource) {
        throw new IllegalStateException("Already have resource");
      }
      engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
      
      hasResource = true;
      copy = cbs.copy();
      incrementPendingCallbacks(copy.size() + 1);

      localKey = key;
      localResource = engineResource;
    }

    engineJobListener.onEngineJobComplete(this, localKey, localResource);

    //发送到主线程处理图片
    for (final ResourceCallbackAndExecutor entry : copy) {
      //executor为之前构建Request时传入的主线程池
      //cb为SingleRequest
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }

  CallResourceReady是一个Runnable对象,其会在主线程执行,它的run方法如下:

public void run() {
      // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
      // (b/136032534).
      synchronized (cb.getLock()) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            //处理图片
            callCallbackOnResourceReady(cb);
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }

  callCallbackOnResourceReady方法的代码如下:

  void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      // cb为SingleRequest
      cb.onResourceReady(engineResource, dataSource, isLoadedFromAlternateCacheKey);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

  onResourceReady方法的代码如下:

private void onResourceReady(
      Resource<R> resource, R result, DataSource dataSource, boolean isAlternateCacheKey) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    ......
    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
        //执行此方法,在UI上展示图片
        //target为之前封装ImageView的ViewTarget
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }

  3.2、展示图片

  在加载到图片之后,Glide会调用ViewTarget的onResourceReady方法,并将加载的图片传入。在前面介绍给,Glide的into方法会将ImageView封装到ViewTarget中,此ViewTarget的onResourceReady方法的代码如下:

  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }

  setResourceInternal方法的代码如下:

  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);
  }

  protected void setResource(@Nullable Drawable resource) {
    //给ImageView设置图片
    view.setImageDrawable(resource);
  }

  至此,Glide加载图片的大体过程就分析结束了。本文对一些较为细节的地方没有深入分析,如: 通过HTTPURLConnection获取图片输入流的具体过程,图片输入流编码为Bitmap的具体过程、图片的变换和缓存过程。之后将会继续完善上述部分。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值