美文网首页
Android Glide源码剖析系列(三)深入理解Glide图

Android Glide源码剖析系列(三)深入理解Glide图

作者: 怡红快绿 | 来源:发表于2022-05-20 07:08 被阅读0次

    Glide源码剖析系列


    为什么选择Glide?

    • 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)
    • 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)Glide可以感知调用页面的生命周期,这就是优势
    • 高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
    • 高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)

    小结:支持图片格式多;Bitmap复用和主动回收;生命周期感应;优秀的缓存策略;加载速度快(Bitmap默认格式RGB565)

    Glide简单使用

    Glide.with(this)
            .load("https://t7.baidu.com/it/u=3779234486,1094031034&fm=193&f=GIF")
            .error(R.drawable.aaa)
            .placeholder(R.drawable.ic_android_black_24dp)
            .fallback(R.drawable.aaa)
            .diskCacheStrategy(DiskCacheStrategy.NONE)
            .skipMemoryCache(true)
            .into(imageView);
    

    源码分析

    上篇文章学习了RequestTracker 如何管理图片加载请求,本文开始分析图片加载请求执行流程。

    #RequestTracker.java
      /** Starts tracking the given request. 把请求添加到requests和pendingRequests*/
      public void runRequest(@NonNull Request request) {
        requests.add(request);
        if (!isPaused) {
          request.begin();  //图片加载请求执行入口
        } else {
          request.clear();
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Paused, delaying request");
          }
          pendingRequests.add(request);
        }
      }
    

    request.begin()方法是请求开始执行的入口,这里的request是SingleRequest类型,所以有必要先搞懂SingleRequest类

    /**
     * 定义:把资源加载到目标的请求
     */
    public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback {
    
      //请求的状态
      private enum Status {
        /** Created but not yet running. */
        PENDING,
        /** In the process of fetching media. */
        RUNNING,
        /** Waiting for a callback given to the Target to be called to determine target dimensions. */
        WAITING_FOR_SIZE,
        /** Finished loading media successfully. */
        COMPLETE,
        /** Failed to load media, may be restarted. */
        FAILED,
        /** Cleared by the user with a placeholder set, may be restarted. */
        CLEARED,
      }
    
      /* 同步锁对象:给请求的操作方法上锁,保证线程安全 */
      private final Object requestLock;
      //监听请求的状态变化
      @Nullable private final RequestListener<R> targetListener;
      //协调一个target上的多个请求
      private final RequestCoordinator requestCoordinator;
    
      private final Context context;
    
      private final GlideContext glideContext;
      
      @Nullable private final Object model;
    
      private final Class<R> transcodeClass;
      //请求的配置参数
      private final BaseRequestOptions<?> requestOptions;
    
      private final int overrideWidth;
    
      private final int overrideHeight;
    
      private final Priority priority;
    
      private final Target<R> target;
    
      @Nullable private final List<RequestListener<R>> requestListeners;
    
      private final TransitionFactory<? super R> animationFactory;
    
      private final Executor callbackExecutor;
    
      @GuardedBy("requestLock")
      private Resource<R> resource;  
    
      @GuardedBy("requestLock")
      private Engine.LoadStatus loadStatus;
    
      @GuardedBy("requestLock")
      private long startTime;
    
      // Volatile because it's accessed outside of a lock and nullable, even though in practice it will
      // always be non-null unless the request is in the object pool.
      private volatile Engine engine;  //图片处理引擎
    
      /* Variables mutated during a request. */
      @GuardedBy("requestLock")
      private Status status;
    
      @GuardedBy("requestLock")
      @Nullable
      private Drawable errorDrawable;  //加载失败显示图
    
      @GuardedBy("requestLock")
      @Nullable
      private Drawable placeholderDrawable;  //占位图
    
      @GuardedBy("requestLock")
      @Nullable
      private Drawable fallbackDrawable;
    
      @GuardedBy("requestLock")
      private int width;
    
      @GuardedBy("requestLock")
      private int height;
    
      @Override
      public void begin() {
        synchronized (requestLock) {  //加锁
          assertNotCallingCallbacks();
          stateVerifier.throwIfRecycled();
          startTime = LogTime.getLogTime();
          if (model == null) {  //注释1
            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;
          }
    
          if (status == Status.RUNNING) {  //注释2
            throw new IllegalArgumentException("Cannot restart a running request"); //直接抛出异常
          }
    
          // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
          // that starts an identical request into the same Target or View), we can simply use the
          // resource and size we retrieved the last time around and skip obtaining a new size, starting
          // a new load etc. This does mean that users who want to restart a load because they expect
          // that the view size has changed will need to explicitly clear the View or Target before
          // starting the new load.
          if (status == Status.COMPLETE) {  //注释3
            onResourceReady(
                resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
            return;
          }
    
          // Restarts for requests that are neither complete nor running can be treated as new requests
          // and can run again from the beginning.
    
          experimentalNotifyRequestStarted(model);
    
          cookie = GlideTrace.beginSectionAsync(TAG);
          status = Status.WAITING_FOR_SIZE;  //状态设为:等待target确定尺寸
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {  //注释4
            onSizeReady(overrideWidth, overrideHeight);
          } else {
            target.getSize(this);
          }
    
          if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
              && canNotifyStatusChanged()) {  //target设置占位图
            target.onLoadStarted(getPlaceholderDrawable());
          }
          if (IS_VERBOSE_LOGGABLE) {
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
          }
        }
      }
    }
    

    逐个分析Request#begin()方法中的if判断语句

    • 注释1:如果资源数据为null,执行onLoadFailed(new GlideException("Received null model"), logLevel)方法;
      private void onLoadFailed(GlideException e, int maxLogLevel) {
        stateVerifier.throwIfRecycled();
        synchronized (requestLock) {  //加锁
          loadStatus = null;
          status = Status.FAILED;  //1.设置请求的状态
    
          isCallingCallbacks = true;
          try {
            // TODO: what if this is a thumbnail request?
            boolean anyListenerHandledUpdatingTarget = false;
            if (requestListeners != null) {
              for (RequestListener<R> listener : requestListeners) {
                anyListenerHandledUpdatingTarget |=
                    listener.onLoadFailed(e, model, target, isFirstReadyResource());
              }
            }
            anyListenerHandledUpdatingTarget |=
                targetListener != null
                    && targetListener.onLoadFailed(e, model, target, isFirstReadyResource());
    
            if (!anyListenerHandledUpdatingTarget) {
              setErrorPlaceholder();  //2.如果不是缩略图请求,设置显示失败占位图
            }
          } finally {
            isCallingCallbacks = false;
          }
    
          notifyLoadFailed();
        }
      }
    
      @GuardedBy("requestLock")
      private void setErrorPlaceholder() {
        if (!canNotifyStatusChanged()) {
          return;
        }
    
        Drawable error = null;
        if (model == null) {
          error = getFallbackDrawable();
        }
        // Either the model isn't null, or there was no fallback drawable set.
        if (error == null) {
          error = getErrorDrawable();
        }
        // The model isn't null, no fallback drawable was set or no error drawable was set.
        if (error == null) {
          error = getPlaceholderDrawable();
        }
        target.onLoadFailed(error);  //3.告诉target资源加载失败,并把错误占位图资源回传给target
      }
    
    1. 设置请求的状态为Status.FAILED;
    2. 如果不是缩略图请求,setErrorPlaceholder()设置显示失败占位图;
    3. 告诉target资源加载失败,并把错误占位图资源回传给target
    • 注释2:请求状态为RUNNING,不允许执行begin()方法
    • 注释3:请求状态为COMPLETE,执行onResourceReady( resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
      @Override
      public void onResourceReady(
          Resource<?> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
        stateVerifier.throwIfRecycled();
        Resource<?> toRelease = null;
        try {
          synchronized (requestLock) {
            loadStatus = null;
            if (resource == null) {  //资源为null,回调onLoadFailed
              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())) {
              toRelease = resource;
              this.resource = null;
              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()) {
              toRelease = resource;  //准备回收resource
              this.resource = null;
              // We can't put the status to complete before asking canSetResource().
              status = Status.COMPLETE;
              GlideTrace.endSectionAsync(TAG, cookie);
              return;
            }
    
            onResourceReady(
                (Resource<R>) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey);
          }
        } finally {
          if (toRelease != null) {
            engine.release(toRelease);
          }
        }
      }
    
      @GuardedBy("requestLock")
      private boolean canSetResource() {
        return requestCoordinator == null || requestCoordinator.canSetImage(this);
      }
    
    1. 如果 resource 或 resource.get() 为空,调用 onLoadFailed(exception);
    2. 如果不允许设置resource,请求状态设为COMPLETE,并准备回收resource
    3. 执行onResourceReady( (Resource<R>) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey);
      @GuardedBy("requestLock")
      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);
            target.onResourceReady(result, animation);
          }
        } finally {
          isCallingCallbacks = false;
        }
    
        notifyLoadSuccess();
        GlideTrace.endSectionAsync(TAG, cookie);
      }
    

    资源加载成功回调target.onResourceReady()方法

    • 注释4:如果通过RequestOption设置的宽高都大于0或者与Target原始宽高相等,则调用onSizeReady(overrideWidth, overrideHeight);;否则重新计算target尺寸,计算完成后依然会调用onSizeReady()方法
      @Override
      public void onSizeReady(int width, int height) {
        stateVerifier.throwIfRecycled();
        synchronized (requestLock) {
          if (status != Status.WAITING_FOR_SIZE) {
            return;
          }
          status = Status.RUNNING;  //请求的状态设为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);
    
          // This is a hack that's only useful for testing right now where loads complete synchronously
          // even though under any executor running on any thread but the main thread, the load would
          // have completed asynchronously.
          if (status != Status.RUNNING) {
            loadStatus = null;
          }
        }
      }
    
    1. 请求的状态设为RUNNING
    2. 图片加载引擎Engine开始加载图片

    到此为止,Request的begin()方法分析完毕,图片加载流程最终交给Engine执行。Engine是整个图片加载流程中一个非常重要的角色,接下来继续阅读源码揭开Engine的神秘面纱。

    #Engine.java
      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,
          boolean isScaleOnlyOrNoTransform,
          Options options,
          boolean isMemoryCacheable,
          boolean useUnlimitedSourceExecutorPool,
          boolean useAnimationPool,
          boolean onlyRetrieveFromCache,
          ResourceCallback cb,
          Executor callbackExecutor) {
        long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
    
        //使用request配置信息构建EngineKey,用于资源缓存
        EngineKey key =
            keyFactory.buildKey(
                model,
                signature,
                width,
                height,
                transformations,
                resourceClass,
                transcodeClass,
                options);
    
        EngineResource<?> memoryResource;
        synchronized (this) {
          memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);  //从内存缓存中查找资源
    
          if (memoryResource == null) {  //缓存中查找不到资源,重用或新建一个新EngineJob
            return waitForExistingOrStartNewJob(
                glideContext,
                model,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                options,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache,
                cb,
                callbackExecutor,
                key,
                startTime);
          }
        }
    
        // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
        // deadlock.
        cb.onResourceReady(
            memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
        return null;
      }
    
     @Nullable
      private EngineResource<?> loadFromMemory(
          EngineKey key, boolean isMemoryCacheable, long startTime) {
        if (!isMemoryCacheable) {
          return null;
        }
    
        EngineResource<?> active = loadFromActiveResources(key);  //正在使用的资源列表中查找
        if (active != null) {
          if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Loaded resource from active resources", startTime, key);
          }
          return active;
        }
    
        EngineResource<?> cached = loadFromCache(key);  //内存缓存中查找资源
        if (cached != null) {
          if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
          }
          return cached;
        }
    
        return null;
      }
    
    1. 使用request配置信息构建EngineKey,用作资源缓存时的key
    2. 从正在使用的资源列表和内存缓存中查找资源
    3. 如果没找到资源,重用或新建一个新EngineJob

    注:Glide著名的图片缓存分为内存缓存和磁盘缓存,这里已经出现了内存缓存,磁盘缓存会在接下来的DecodeJob中处理。关于图片缓存机制会专门撸一篇文章,所以本文中会略过缓存处理相关逻辑。

      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);
    
        jobs.put(key, engineJob);
    
        engineJob.addCallback(cb, callbackExecutor);
        engineJob.start(decodeJob);
    
        if (VERBOSE_IS_LOGGABLE) {
          logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
      }
    

    从EngineJob缓存列表中查找是否有可重用的EngineJob,如果有直接重用;否则新建一个EngineJob,并开启该JobengineJob.start(decodeJob);

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

    解码工作是耗时操作,不能在主线程操作,因此把decodeJob提交到线程池执行

    class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable,
     Comparable<DecodeJob<?>>, Poolable {
      @Override
      public void run() {
        DataFetcher<?> localFetcher = currentFetcher;
        try {
          if (isCancelled) {
            notifyFailed();
            return;
          }
          runWrapped();
        } catch (CallbackException e) {
          throw e;
        } catch (Throwable t) {
          // 异常处理
        } finally {
          //清理工作
        }
      }
    }
    
      private void runWrapped() {
        switch (runReason) {
          case INITIALIZE:
            stage = getNextStage(Stage.INITIALIZE);  //1
            currentGenerator = getNextGenerator();  //2
            runGenerators();  //3
            break;
          case SWITCH_TO_SOURCE_SERVICE:
            runGenerators();
            break;
          case DECODE_DATA:
            decodeFromRetrievedData();
            break;
          default:
            throw new IllegalStateException("Unrecognized run reason: " + runReason);
        }
      }
    
      private Stage getNextStage(Stage current) {
        switch (current) {
          case INITIALIZE:
            return diskCacheStrategy.decodeCachedResource()
                ? Stage.RESOURCE_CACHE
                : getNextStage(Stage.RESOURCE_CACHE);
          case RESOURCE_CACHE:
            return diskCacheStrategy.decodeCachedData()
                ? Stage.DATA_CACHE
                : getNextStage(Stage.DATA_CACHE);
          case DATA_CACHE:
            // Skip loading from source if the user opted to only retrieve the resource from cache.
            return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
          case SOURCE:
          case FINISHED:
            return Stage.FINISHED;
          default:
            throw new IllegalArgumentException("Unrecognized stage: " + current);
        }
      }
    
      private DataFetcherGenerator getNextGenerator() {
        switch (stage) {
          case RESOURCE_CACHE:
            return new ResourceCacheGenerator(decodeHelper, this);  //缓存的处理过的资源的生成器
          case DATA_CACHE:
            return new DataCacheGenerator(decodeHelper, this);  //缓存的原始资源的生成器
          case SOURCE:
            return new SourceGenerator(decodeHelper, this);  //使用modelLoader和model获取原始资源的生成器
          case FINISHED:
            return null;
          default:
            throw new IllegalStateException("Unrecognized stage: " + stage);
        }
      }
    
    1. 计算nextStage
    2. 根据nextStage获取对应的Generator
    3. 执行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;
          }
        }
        // We've run out of stages and generators, give up.
        if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
          notifyFailed();
        }
    
        // Otherwise a generator started a new load and we expect to be called back in
        // onDataFetcherReady.
      }
    

    while循环语句:图片可能来自于磁盘缓存,也可能需要开启任务去获取。我们分析的是没有缓存的情况,所以要先确定使用哪种Generator来生成资源,然后继续查看加载流程,此处以SourceGenerator为例:

    继续分析sourceGenerator.startNext()

    #SourceGenerator.java
      @Override
      public boolean startNext() {
       //跳过缓存相关逻辑,分析没有缓存时的加载流程
        while (!started && hasNextModelLoader()) {  //注释5
          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;
      }
    

    我们知道资源加载由ModelLoader才能完成,先分析一下ModelLoader类

    public interface ModelLoader<Model, Data> {
    
      class LoadData<Data> {
        public final Key sourceKey;  //用于缓存的key
        public final List<Key> alternateKeys;
        public final DataFetcher<Data> fetcher;  //数据抓取器
    
        public LoadData(@NonNull Key sourceKey, @NonNull DataFetcher<Data> fetcher) {
          this(sourceKey, Collections.<Key>emptyList(), fetcher);
        }
    
        public LoadData(
            @NonNull Key sourceKey,
            @NonNull List<Key> alternateKeys,
            @NonNull DataFetcher<Data> fetcher) {
          this.sourceKey = Preconditions.checkNotNull(sourceKey);
          this.alternateKeys = Preconditions.checkNotNull(alternateKeys);
          this.fetcher = Preconditions.checkNotNull(fetcher);
        }
      }
    
      @Nullable
      LoadData<Data> buildLoadData(
          @NonNull Model model, int width, int height, @NonNull Options options);
    
      boolean handles(@NonNull Model model);
    }
    

    原来真正干活的是内部类LoadData,其中的sourceKey用于缓存资源,fetcher是数据抓取器。

    回到sourceGenerator.startNext()注释5循环语句:

    #DecodeHelper.java
      List<LoadData<?>> getLoadData() {
        if (!isLoadDataSet) {
          isLoadDataSet = true;
          loadData.clear();
          List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
          //noinspection ForLoopReplaceableByForEach to improve perf
          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;
      }
    

    根据model类型从ModelLoader注册列表中筛选出符合要求的ModelLoader列表,最终筛选出能干活的LoadData去执行startNextLoad(loadData)

    #SourceGenerator.java
      private void startNextLoad(final LoadData<?> toStart) {
        //注释6:加载资源
        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);
                }
              }
            });
      }
    
    注释6:最终加载工作交由Fetcher处理,由于我们传入的model是String类型的图片地址,所以这里干活的是HttpUrlFetcher,进入HttpUrlFetcher#loadData():
    #HttpUrlFetcher.java
      @Override
      public void loadData(
          @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        try {
          InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
          callback.onDataReady(result);
        } catch (IOException e) {
          callback.onLoadFailed(e);
        } finally {
        }
      }
    

    使用loadDataWithRedirects()方法获取网络资源的InputStream,并且把结果回调给callback.onDataReady(result)方法,代码执行到注释6处的onDataReady()回调方法,内部调用onDataReadyInternal(toStart, data) 继续处理inputStream

    #SourceGenerator.java
      @Synthetic
      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 {
          cb.onDataFetcherReady(
              loadData.sourceKey,
              data,
              loadData.fetcher,
              loadData.fetcher.getDataSource(),
              originalKey);
        }
      }
    

    由于我们是禁用缓存的,直接进入到else语句,这里又是一个方法回调,这个回调方法在DecodeJob中实现

    #DecodeJob.java
      @Override
      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) {
          runReason = RunReason.DECODE_DATA;
          callback.reschedule(this);
        } else {
          GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            decodeFromRetrievedData();
          } finally {
            GlideTrace.endSection();
          }
        }
      }
    

    这里需要经历一系列的方法调用来处理数据:decodeFromRetrievedData() -> decodeFromData(currentFetcher, currentData, currentDataSource) -> decodeFromFetcher(data, dataSource)

    #DecodeJob.java
      @SuppressWarnings("unchecked")
      private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
          throws GlideException {
        LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());  //根据data类型获取LoadPath
        return runLoadPath(data, dataSource, path);
      }
    
      private <Data, ResourceType> Resource<R> runLoadPath(
          Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
          throws GlideException {
        Options options = getOptionsWithHardwareConfig(dataSource);
        DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
        try {
          // ResourceType in DecodeCallback below is required for compilation to work with gradle.
          return path.load(
              rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
        } finally {
          rewinder.cleanup();
        }
      }
    
    #LoadPath.java
      public Resource<Transcode> load(
          DataRewinder<Data> rewinder,
          @NonNull Options options,
          int width,
          int height,
          DecodePath.DecodeCallback<ResourceType> decodeCallback)
          throws GlideException {
        List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
        try {
          return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
        } finally {
          listPool.release(throwables);
        }
      }
    
      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;
      }
    
    #DecodePath.java
      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);
      }
    

    目标资源经过一系列解码(decode)和转换(transform)操作,最终得到我们需要的BitmapDrawableResource并一层层返回给调用发起的地方,也就是decodeFromRetrievedData()方法,我们回到该方法:

      private void decodeFromRetrievedData() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey(
              "Retrieved data",
              startFetchTime,
              "data: "
                  + currentData
                  + ", cache key: "
                  + currentSourceKey
                  + ", fetcher: "
                  + currentFetcher);
        }
        Resource<R> resource = null;
        try {
          resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
          e.setLoggingDetails(currentAttemptingKey, currentDataSource);
          throwables.add(e);
        }
        if (resource != null) {
          notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
        } else {
          runGenerators();
        }
      }
    

    把decode得到的结果resource传入notifyEncodeAndRelease()方法

      private void notifyEncodeAndRelease(
          Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
        GlideTrace.beginSection("DecodeJob.notifyEncodeAndRelease");
        try {
          if (resource instanceof Initializable) {
            ((Initializable) resource).initialize();  //1
          }
    
          Resource<R> result = resource;
          LockedResource<R> lockedResource = null;
          if (deferredEncodeManager.hasResourceToEncode()) {
            lockedResource = LockedResource.obtain(resource);
            result = lockedResource;
          }
    
          notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);  //2
    
          stage = Stage.ENCODE;
          try {
            if (deferredEncodeManager.hasResourceToEncode()) {
              deferredEncodeManager.encode(diskCacheProvider, options);  
            }
          } finally {
            if (lockedResource != null) {
              lockedResource.unlock();
            }
          }
          // Call onEncodeComplete outside the finally block so that it's not called if the encode
          // process
          // throws.
          onEncodeComplete();
        } finally {
          GlideTrace.endSection();
        }
      }
    
    1. 执行绘制Bitmap的准备工作
      @Override
      public void initialize() {
        drawable.getBitmap().prepareToDraw();
      }
    
    1. 图片资源decode完毕,可以拿去显示图片啦

    跨越千山万水马上到达终点了,怀着激动的心情继续分析代码:

      private void notifyComplete(
          Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
        setNotifiedOrThrow();
        callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
      }
    

    onResourceReady()方法在EngineJob中实现。继续追踪代码:

    #EngineJob.java
      @Override
      public void onResourceReady(
          Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
        synchronized (this) {
          this.resource = resource;
          this.dataSource = dataSource;
          this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
        }
        notifyCallbacksOfResult();
      }
    
      void notifyCallbacksOfResult() {
        ResourceCallbacksAndExecutors copy;
        Key localKey;
        EngineResource<?> localResource;
        synchronized (this) {
          //我们省略了异常情况的处理代码和一些注释代码
    
          engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener); //1
         
          hasResource = true;
          copy = cbs.copy();  //2
          incrementPendingCallbacks(copy.size() + 1);
    
          localKey = key;
          localResource = engineResource;
        }
    
        engineJobListener.onEngineJobComplete(this, localKey, localResource);  //3
    
        for (final ResourceCallbackAndExecutor entry : copy) {
          entry.executor.execute(new CallResourceReady(entry.cb));  //4
        }
        decrementPendingCallbacks();
      }
    
    1. engineResource 是资源的一个包装类,负责计算资源被引用的次数,次数为0的时候可以回收资源
    2. copy内部包装的是Executors.mainThreadExecutor()主线程池,方便切换到主线程
    3. EngineJob执行完毕,把加载的资源加入内存缓存并且从EngineJob缓存列表移除当前job
      @Override
      public synchronized void onEngineJobComplete(
          EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
        // A null resource indicates that the load failed, usually due to an exception.
        if (resource != null && resource.isMemoryCacheable()) {
          activeResources.activate(key, resource);
        }
    
        jobs.removeIfCurrent(key, engineJob);
      }
    
    1. 把任务切换到主线程执行,也就是说之前的操作都是在子线程中处理
        @Override
        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();
            }
          }
        }
    
      @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, isLoadedFromAlternateCacheKey);
        } catch (Throwable t) {
          throw new CallbackException(t);
        }
      }
    

    最终还是回到了SingleRequest的onResourceReady(),也就是文章开头介绍的begin()方法注释3部分,太远了重新贴一下代码吧!

     @GuardedBy("requestLock")
      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;
          //1 begin
          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);
        //1 end
    
          if (!anyListenerHandledUpdatingTarget) {  //2
            Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
            target.onResourceReady(result, animation);  
          }
        } finally {
          isCallingCallbacks = false;
        }
    
        notifyLoadSuccess();
        GlideTrace.endSectionAsync(TAG, cookie);
      }
    
    1. 如果设置了requestListener或targetListener,则调用它们的onResourceReady()回调方法;
    2. anyListenerHandledUpdatingTarget含义:是否有listener处理,即listener.onResourceReady()方法的返回值。
      如果anyListenerHandledUpdatingTarget==false,进入ImageViewTarget#onResourceReady()方法:
      @Override
      public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
        if (transition == null || !transition.transition(resource, this)) {
          setResourceInternal(resource);  
        } else {
          maybeUpdateAnimatable(resource);
        }
      }
    
      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);
      }
    

    进入DrawableImageViewTarget#setResource(resource)方法:

      @Override
      protected void setResource(@Nullable Drawable resource) {
        view.setImageDrawable(resource);
      }
    

    最终资源被成功设置到ImageView上,图片加载流程结束。

    图片加载流程图

    如果有错误或理解不到位的地方,欢迎批评指正。

    Tips:整个加载流程的代码调用真的是很复杂,涉及到Callback回调、抽象方法实现、还有参数N次传递后很难定位来源,建议一边调试程序一边跟踪代码,可以直接跳转到执行点。

    相关文章

      网友评论

          本文标题:Android Glide源码剖析系列(三)深入理解Glide图

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