源码解析之Glide 4.9 图片加载流程下

接续,开始解析数据

onDataFetcherReady方法中主要工作

  1. 解析获取的数据
  2. 返回图片资源

下面接着看

DecodeJob#decodeFromData

  private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
      DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }
  
   @SuppressWarnings("unchecked")
  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
      ==================================================
      = 获取当前数据类的解析器LoadPath,此时的data为InputStream对象 
      ===================================================
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    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();
    }
  }
  
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 {
      ============================================
      = 调用DecodePath.decode真正进行数据解析
      =============================================
        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;
  }
  
 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);
    // 该transcoder为BitmapDrawableTranscoder
    return transcoder.transcode(transformed, options);
  }
  • LoadPath的load方法最终会调用DecodePath的decode来解析数据,DecodePath的decode的主要工作就是获取到Resource对象,然后还要将Resource对象转化成LazyBitmapDrawableResource。考虑到篇幅问题,在这里就不分析如何得到Resource对象,只分析如何将数据转化为目标格式,可以通过Glide构造中的注册表中找出Bitmap转化成Drawable的转化器为BitmapDrawableTranscoder,所以实际上调用了BitmapDrawableTranscoder的transcode来进行转换。

BitmapDrawableTranscoder#transcode

  public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
      @NonNull Options options) {
    //获取LazyBitmapDrawableResource对象  
    return LazyBitmapDrawableResource.obtain(resources, toTranscode);
  }

LazyBitmapDrawableResource#obtain

  public static Resource<BitmapDrawable> obtain(
      @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
    if (bitmapResource == null) {
      return null;
    }
	//创建了一个LazyBitmapDrawableResource对象
    return new LazyBitmapDrawableResource(resources, bitmapResource);
  }
  
  public BitmapDrawable get() {
    //返回一个BitmapDrawable对象
    return new BitmapDrawable(resources, bitmapResource.get());
  }

  • 追踪下去可以发现transcode最终会得到一个封装了Resource的对象,然后看LazyBitmapDrawableResource的get方法,可以得到一个BitmapDrawable对象,即目标格式。到这里就成功将数据解析成LazyBitmapDrawableResource对象。

在主线程中显示图片

DecodeJob#decodeFromRetrievedData

   private void decodeFromRetrievedData() {
    ....
    try {
	  //解析成功后resource为封装了Resource<Bitmap>的LazyBitmapDrawableResource对象
      //可通过get方法获取到BitmapDrawable对象
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
	  //通知外界资源获取成功	
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    .....
    //重点关注
    notifyComplete(result, dataSource);
    ......
    
  }

  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
	====================================================================
	= 回调,注意此时的callback为EngineJob(可回头看Engine中DecodeJob的创建)
	====================================================================
    callback.onResourceReady(resource, dataSource);
  }

回调数据
这个callback哪个对象呢?我们得找出赋值的地方

  //重点关注倒数第二个参数,callback的类型为CallBack
  DecodeJob<R> init(
      GlideContext glideContext,
      Object model,
      EngineKey loadKey,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      boolean onlyRetrieveFromCache,
      Options options,
      Callback<R> callback,
      int order) {
    decodeHelper.init(
        glideContext,
        model,
        signature,
        width,
        height,
        diskCacheStrategy,
        resourceClass,
        transcodeClass,
        priority,
        options,
        transformations,
        isTransformationRequired,
        isScaleOnlyOrNoTransform,
        diskCacheProvider);
    this.glideContext = glideContext;
    this.signature = signature;
    this.priority = priority;
    this.loadKey = loadKey;
    this.width = width;
    this.height = height;
    this.diskCacheStrategy = diskCacheStrategy;
    this.onlyRetrieveFromCache = onlyRetrieveFromCache;
    this.options = options;
    this.callback = callback;
    this.order = order;
    this.runReason = RunReason.INITIALIZE;
    this.model = model;
    return this;
  }

  • 很容易的我们发现在init方法会为callback赋值,这时候得记住callback参数的具体位置为倒数第二个。这时候你会想:哪里会调用DecodeJob的init方法呢?然后揣摩:既然是赋值估计会在构建DecodeJob时候会调用到。于是问题就转换为:上文是在哪个地方构建了DecodeJob?然后心里默念:DecodeJob是用来执行任务的,所以应该在构建任务的时候会调用!(不过大多数的情形是:脑子里一片空白,压根想不出来,反正笔者在这里就想不出来。所以这时候就可以直接往上找到DecodeJob首次出现的位置),最终是会在Engine的load中找到DecodeJob的构建

Engine#load

public synchronized <R> LoadStatus load(....){
    //重点关注倒数最后一个参数
	DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

}
    //重点关注最后一个参数
    <R> DecodeJob<R> build(GlideContext glideContext,
        Object model,
        EngineKey loadKey,
        Key signature,
        int width,
        int height,
        Class<?> resourceClass,
        Class<R> transcodeClass,
        Priority priority,
        DiskCacheStrategy diskCacheStrategy,
        Map<Class<?>, Transformation<?>> transformations,
        boolean isTransformationRequired,
        boolean isScaleOnlyOrNoTransform,
        boolean onlyRetrieveFromCache,
        Options options,
        DecodeJob.Callback<R> callback) {
      DecodeJob<R> result = Preconditions.checkNotNull((DecodeJob<R>) pool.acquire());
      return result.init(
          glideContext,
          model,
          loadKey,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          callback,
          creationOrder++);
    }
  }

  • 在上面的代码中首先调用了DecodeJobFactory的build方法来构建DecodeJob,DecodeJobFactory是Engine的内部类,然后接着看DecodeJobFactory的build方法,哇!跟我们想的完全一样!build方法中调用了DecodeJob的init方法,找到后可别忘了我们的任务是干嘛的!找到callback的值,于是看回build的callback的参数位置,在最后一个,然后往回看Engine的load中调用build的最后一个参数!engineJob!没错最后找到的callback的类型应该是EngineJob类型的,其实EngineJob是实现了DecodeJob.Callback接口的。所以接下来就会回调EngineJob的onResourceReady方法
  • EngineJob#onResourceReady
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
	//重点关注
    notifyCallbacksOfResult();
  }

  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      ......

	  //重点关注cbs的类型
	  //查找cbs里面的类型
      copy = cbs.copy();
      .....
    }
    //通知上层Engine的任务完成了
    listener.onEngineJobComplete(this, localKey, localResource);

    for (final ResourceCallbackAndExecutor entry : copy) {
	  //回调给ImageViewTarget来展示资源
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }

回到主线程

  • 又到了确定参数类型的时刻了,首先我们先确定EngineJob的onResourceReady方法中最重要的代码片
	for (final ResourceCallbackAndExecutor entry : copy) {
	  //回调给ImageViewTarget来展示资源
      entry.executor.execute(new CallResourceReady(entry.cb));
    }

在确定分析线程池的execute的方法前,我们需要做的事有:

  • 确定entry.executor类型
  • 确定entry.cb类型
    现在我们知道entry为ResourceCallbackAndExecutor方法,所以我们来看看这个类以及构造器

ResourceCallbackAndExecutor

  static final class ResourceCallbackAndExecutor {
    final ResourceCallback cb;
    final Executor executor;

    ResourceCallbackAndExecutor(ResourceCallback cb, Executor executor) {
      this.cb = cb;
      this.executor = executor;
    }
  }

可以发现executor和cb都是ResourceCallbackAndExecutor中的成员变量,在构造时被赋值,所以我们需要找到构造ResourceCallbackAndExecutor对象的地方,自然而然我们会锁定上面copy这个变量

EngineJob

 
final ResourceCallbacksAndExecutors cbs = new ResourceCallbacksAndExecutors();

void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      ......

	  //重点关注cbs的类型
	  //查找cbs里面的类型
      copy = cbs.copy();
      .....
    }
    .....
  }

    ResourceCallbacksAndExecutors copy() {
      return new ResourceCallbacksAndExecutors(new ArrayList<>(callbacksAndExecutors));
    }
	 ======================================
     = cbs赋值的地方
     ======================================
    synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
    stateVerifier.throwIfRecycled();
	//此时的cb为singleRequest类型,其实现了ResourceCallback接口
	//callbackExecutor就是绑定了主线程Handler的线程池
	//cbs的类型为ResourceCallbacksAndExecutors
	//add的内部实现就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量
    //然后再add到cbs中    
    cbs.add(cb, callbackExecutor);
    ......
     
  }


    void add(ResourceCallback cb, Executor executor) {
      callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
    }


  • 让我们看看copy赋值调用的地方,就是调用了ResourceCallbacksAndExecutors类型的cbs的copy方法,copy其实就是创建了ResourceCallbacksAndExecutor集合,这个集合其实就是cbs,我们还需要找到cbs赋值的地方,找半天后你会发现在addCallback方法中会找到cbs的add方法,add方法的内部实现其实就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量中,所以我们还得确定add方法的两个参数是什么?不知道你是否还有印象,当初在构建任务时我们有专门提到过这个addCallback方法,让我们重新看看Engine的load方法。

Engine#load

    ....
    //调用addCallback()注册了一个ResourceCallback
	//这里的cb是load方法的倒数第二个参数,load是在singleRequest的onSizeReady()调用的
	//查看后cb为singleRequest类型
	//重新看回EngineJob的addCallback方法
    engineJob.addCallback(cb, callbackExecutor);
	//在子线程中执行DecodeJob的run方法
    engineJob.start(decodeJob);

要想确定cb和callbackExecutor的类型,我们还需要一步一步往回走

  //特别关注最后两个参数
  public synchronized <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)

SingleRequest#onSizeReady

    loadStatus =
         ============================================================================
    	= 重点关注倒数第二个参数,传入的是this,即SingleRequest对象,其实现了ResourceCallback接口
    	= 重点关注倒数第一个参数,传入有绑定主线程的Handle的r线程池callbackExectuter
    	============================================================================
        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);

  • SingleRequest的onSizeReady中我们确定了cb的类型为SingleRequest对象,另外一个参数的话由于篇幅原因就不一一贴出代码了(都是上文贴过的代码),你可以直接从onSizeReady方法往回看,上面的注释也会提到,最后你会发现这个callbackExecutor其实就是我们一开始提到的含有绑定主线程Handler的线程池。让我们回到最初的地方

EngineJob#onResourceReady

	for (final ResourceCallbackAndExecutor entry : copy) {
	  //回调给ImageViewTarget来展示资源
       //entry.cb为singleRequest类型类型
	   //entry.executor就是含有绑定了主线程的Handler的线程池,即MAIN_THREAD_EXECUTOR
      entry.executor.execute(new CallResourceReady(entry.cb));
    }

所以我们来看看Executors的mainThreadExecutor方法(忘记的重新看上面的2.2)

private static final Executor MAIN_THREAD_EXECUTOR =
      new Executor() {
       //绑定主线程的Looper
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {  
          handler.post(command);
        }
      };

public static Executor mainThreadExecutor() {
    return MAIN_THREAD_EXECUTOR;
  }

根据Handler机制的相关知识,当调用MAIN_THREAD_EXECUTOR的execute方法后将会在主线程中执行CallResourceReady对象的run方法。所以我们看看CallResourceReady的run方法

显示图片

EngineJob.CallResourceReady#run

    public void run() {
      synchronized (EngineJob.this) {
        if (cbs.contains(cb)) {
          // Acquire for this particular callback.
          engineResource.acquire();
		  ======================================
		  = 重点关注,此时cb为SingleRequest对象
		  ======================================
          callCallbackOnResourceReady(cb);
          removeCallback(cb);
        }
        decrementPendingCallbacks();
      }
    }
  }

  synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
    ======================================
    = 回调,将目标数据回调出去
    = 此时的cb为singleRequest类型
    ======================================
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

又来到了我们熟悉的回调了,此时的cb是SingleRequest类型,我们已经在上文分析过了。所以会调用SingleRequest的onResourceReady方法

SingleRequest#onResourceReady

  public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
    .......
    ============================
    = 重点关注
    ============================
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

  private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    //第一次加载
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (glideContext.getLogLevel() <= Log.DEBUG) {
      Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
          + dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
          + LogTime.getElapsedMillis(startTime) + " ms");
    }

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
	  //如果在使用时设置listener的话,就会回调其中的onResourceReady
      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为DrawableImageViewTarget
        =======================================
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }
     ============================    
     = 通知加载成功
     ============================
    notifyLoadSuccess();
  }

这里我们只需要关注target.onResourceReady(result, animation)这句代码,target对象为DrawableImageViewTarget,所以会调用DrawableImageViewTarget的onResourceReady方法,但是因为DrawableImageViewTarget是没有onResourceReady这个方法的,所以应该是在其父类ImageViewTarget中

ImageViewTarget

  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
     //是否有动画效果 
    if (transition == null || !transition.transition(resource, this)) {
	 ============================
	 = 重点关注,静态图	
     ============================
      setResourceInternal(resource);
    } else {
    =======
    = gif  
    =======
      maybeUpdateAnimatable(resource);
    }
  }

  private void setResourceInternal(@Nullable Z resource) {
    //调用setResource来展示照片
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }

  //此方法为抽象方法,由子类实现,由于分析的是静态图,故实现的子类应该为DrawableImageViewTarget
  protected abstract void setResource(@Nullable Z resource);

这里我们以正常的静态图为例子,所以接下来会调用setResourceInternal(resource)方法,然后继续调用setResource(resource)方法来展示图片,setResource在ImageViewTarget为抽象方法,所以我们继续看回子类DrawableImageViewTarget的实现

DrawableImageViewTarget#setResource

  protected void setResource(@Nullable Drawable resource) {
    //成功展示照片
    view.setImageDrawable(resource);
  }

小结
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值