IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Glide源码(4.11.0)主线流程梳理(二)---load&into方法的内部逻辑 -> 正文阅读

[移动开发]Glide源码(4.11.0)主线流程梳理(二)---load&into方法的内部逻辑

load 源码梳理

根据上篇文章对with方法的梳理可以知道,Glide.with(this) 返回的是RequestManager对象,所以load方法在RequestManager类里面,现在我们分析一下load方法

public class RequestManager
    implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
	  @NonNull
	  @CheckResult
	  public RequestBuilder<Drawable> asDrawable() {
	    return as(Drawable.class);
	  }
	
	  @NonNull
	  @CheckResult
	  @Override
	  public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
	    return asDrawable().load(bitmap);
	  }
	
	  @NonNull
	  @CheckResult
	  @Override
	  public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
	    return asDrawable().load(drawable);
	  }
	
	  @NonNull
	  @CheckResult
	  @Override
	  public RequestBuilder<Drawable> load(@Nullable String string) {
	    return asDrawable().load(string);
	  }
	// ...
	  @NonNull
	  @CheckResult
	  public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
	    return new RequestBuilder<>(glide, this, resourceClass, context);
	  }
  }

从上面的代码可见,asDrawable()方法的主要作用就是构建RequestBuilder;
代码拆开来看,

// 伪代码
public RequestBuilder<Drawable> load(@Nullable String string) {
	    RequestBuilder requestBuilder = asDrawable();
		requestBuilder = requestBuilder.load(string);
	    return requestBuilder;
	  }

下面进入RequestBuilder类,看一下RequestBuilder.load(string)方法;

public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
    
  public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return loadGeneric(resourceId).apply(signatureOf(AndroidResourceSignature.obtain(context)));
  }

  @NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;// 相当于传递过来的资源url
    isModelSet = true;// 标记已经加载过资源
    return this;// 返回RequestBuilder
  }

	//这个主要是调用父类的方法,初始化 配置信息
  @Override
  public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    return super.apply(requestOptions);
  }
}

至此,load方法的主线流程就差不多完事了,主要就是构建RequestBuilder,为了下一步into做准备

into() 源码梳理

这里才算是真正进入Glide源码的核心之处
由于load方法返回的是RequestBuilder,所以 into方法肯定是在RequestBuilder类里面

RequestBuilder.java

  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();// 主线程检查
    Preconditions.checkNotNull(view);// 目标控件  空检查
	//根据布局文件里面scaleType属性的设置,重置RequestOptions
    BaseRequestOptions<?> requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }
//调用 into 重载函数,创建一个 ViewTarget
    return into(
    //调用 buildImageViewTarget 构建一个 ImageView 类型的 Target(Bitmap/Drawable)
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

上面代码就两大步:
第一步:先拿到当前 ImageView getScaleType 类型的属性,然后重新 clone 一个进行配置;
第二步:调用 into 重载继续构建;

  • 先来看下into方法的第一个参数 glideContext.buildImageViewTarget 是怎么构建出来 ImageViewTarget 的:
  @NonNull
  public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }
public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  public <Z> ViewTarget<ImageView, Z> buildTarget(
      @NonNull ImageView view, @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
    //如果目标的编码类型属于 Bitmap 那么就创建一个 Bitmap 类型的 ImageViewTarget
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
    //如果目标的编码类型属于 Drawable 那么就创建一个 Drawable 类型的 ImageViewTarget
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }
}

注意:上面 生成Target 的时候注意一下,只要调用了 asBitmap 才会执行生成BitmapImageViewTarget ,所以这里我们关注 Drawable 类型就行了,我们就先简单看看这个 target 内部怎么实现的

public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {

  public DrawableImageViewTarget(ImageView view) {
    super(view);
  }

  /** @deprecated Use {@link #waitForLayout()} instead. */
  // Public API.
  @SuppressWarnings({"unused", "deprecation"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }

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

这里DrawableImageViewTarget 继承 ImageViewTarget,重写了setResource方法,这里是显示图片到控件上的逻辑,记住这里

  • 继续重载into方法

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    //这里的 isModelSet 是在 load 的时候赋值为 true 的,所以不会抛异常
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
		//为这个 http://xxx.png 生成一个 Glide request 请求
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
		//相当于拿到上一个请求
    Request previous = target.getRequest();// 先取Request,
    //下面的几行说明是否与上一个请求冲突,一般不用管 直接看下面 else 判断
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
        // 意思就是说 如果当前请求跟上一次的请求是同一个,那就释放本次请求,执行上一个请求,
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
	//清理掉目标请求管理
    requestManager.clear(target);
    //重新为目标设置一个 Glide request 请求
    target.setRequest(request);
    //最后是调用 RequestManager 的 track 来执行目标的 Glide request 请求
    requestManager.track(target, request);

    return target;
  }

以上核心就两个点:

  • 第一点:为 target buildRequest 构建一个 Glide request 请求;
  • 第二点:将构建出来的 Request 交于 RequestManager 来执行

简单的来看下怎么构建的 Request:

  private Request buildRequest(...) {
    return buildRequestRecursive(...省略参数);
  }
  //  .... 一系列的方法调用,最终执行到下面的方法
    private Request obtainRequest(...省略参数) {
    return SingleRequest.obtain(...省略参数);
  }

最终是调用了SingleRequest.obtain方法,得到Request之后,交给RequestManager执行requestManager.track(target, request);

  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
     //添加一个目标任务  
  	targetTracker.track(target);
  	//执行 Glide request
    requestTracker.runRequest(request);
  }
  public void runRequest(@NonNull Request request) {
    //添加一个请求
    requests.add(request);
    //是否暂停
    if (!isPaused) {
      //没有暂停,开始调用 Request begin 执行
      request.begin();
    } else {
      //如果调用了 暂停,清理请求
      request.clear();
      pendingRequests.add(request);
    }
  }

继续查看Request的执行begin()方法,
在这里插入图片描述
前面已经备注得到的Request是 SingleRequest,所以,在点击begin方法的时候进入了接口Request里面的begin方法,这时候去找实现类,就应该找 SingleRequest的begin方法;

SingleRequest.java

  @Override
  public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      if (model == null) {
      //检查外部调用的尺寸是否有效
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          width = overrideWidth;
          height = overrideHeight;
        }
        //失败的回调
        int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
        onLoadFailed(new GlideException("Received null model"), logLevel);
        return;
      }

      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }
      if (status == Status.COMPLETE) {//表示资源准备好了
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }
      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      //这里表示大小已经准备好了---去寻找缓存,准备资源
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        target.getSize(this);
      }

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

大小准备好之后 去寻找缓存,准备资源
onSizeReady

  @Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      // ... 
      loadStatus = engine.load(...省略参数);
              // ...
    }
  }

Engine.java
engine.load

public <R> LoadStatus load(...) {
// 拿到 key
    EngineKey key = keyFactory.buildKey(...);
    EngineResource<?> memoryResource;
    synchronized (this) {
    // 去内存查找
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
      if (memoryResource == null) {//内存没有找到,执行一个新的任务
        return waitForExistingOrStartNewJob(...);
      }
    }
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }
  // 执行已经存在的任务 或者 开启一个新任务
  private <R> LoadStatus waitForExistingOrStartNewJob(...) {
    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(...);
    DecodeJob<R> decodeJob = decodeJobFactory.build(...);

    //把当前需要执行的 key 添加进缓存
    jobs.put(key, engineJob);
	//执行任务的回调
    engineJob.addCallback(cb, callbackExecutor);
    //开始执行。
    engineJob.start(decodeJob);
    // ...
    return new LoadStatus(cb, engineJob);
  }

查找内存的过程

  @Nullable
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    if (!isMemoryCacheable) {
      return null;
    }
	// 查找活动缓存
    EngineResource<?> active = loadFromActiveResources(key);
    if (active != null) {
      // 活动缓存有,就返回
      return active;
    }
	// 活动缓存没找到,查找内存缓存
    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      // 内存缓存有,就返回
      return cached;
    }
    // 活动缓存、内存缓存都没有,就返回null
    return null;
  }
  // 查找内存缓存
 private EngineResource<?> loadFromCache(Key key) {
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      // 如果内存缓存找到了,就放到活动缓存里面去
      //此处注意,是剪切,意思就是 内存缓存和活动缓存只能有一处,不能共存,
      // 详情请继续查看activate方法
      activeResources.activate(key, cached);
    }
    return cached;
  }

通过 engine.load 这个函数里面的逻辑,同学们我们可以总结3点:

  1. 先构建请求或者缓存 KEY ;

  2. 根据 KEY 从内存缓存中查找对应的资源数据(ActiveResources(活动缓存,内部是一个 Map 用弱引用持有),LruResourceCache),如果有就回调 对应监听的 onResourceReady 表示数据准备好了。

  3. 从执行缓存中查找对应 key 的任务

    1. 如果找到了,就说明已经正在执行了,不用重复执行。

    2. 没有找到,通过 EngineJob.start 开启一个新的请求任务执行。

下面我们就来看下 engineJob.start 具体执行逻辑:
engineJob.start(decodeJob);

  public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    // 从线程池里得到线程
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
        //开始执行
    executor.execute(decodeJob);
  }

通过 DecodeJob 源码得知,它是实现的 Runnable 接口,这里 GlideExecutor 线程池开始执行,就会启动 DecodeJob 的 run 函数,我们跟踪 run 的实现:

class DecodeJob<R> implements Runnable ...{
  @Override
  public void run() {
    // ...
      if (isCancelled) {
        notifyFailed();
        return;
      }
      // 开始执行
      runWrapped();
      // ...   
  }
}
 private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        //获取资源状态
        stage = getNextStage(Stage.INITIALIZE);
        //根据当前资源状态,获取资源执行器
        currentGenerator = getNextGenerator();
        //执行
        runGenerators();
        break;
      ...
    }
  }

  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        //如果外部调用配置了资源缓存策略,那么返回 Stage.RESOURCE_CACHE
       	//否则继续调用 Stage.RESOURCE_CACHE 执行。
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        //如果外部配置了源数据缓存,那么返回 Stage.DATA_CACHE
        //否则继续调用 getNextStage(Stage.DATA_CACHE)
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        //如果只能从缓存中获取数据,则直接返回 FINISHED,否则,返回SOURCE。
        //意思就是一个新的资源
        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);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

由于我们什么都没有配置,返回的是 SourceGenerator 源数据执行器。继续下面代码执行:
runGenerators()

  private void runGenerators() {
    // ... 
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();
      // ...
  }

着重看 while循环里面的currentGenerator.startNext();
DataFetcherGenerator 是一个抽象类,那么这里执行的实现类是哪一个,可以参考下面说明:

Stage.RESOURCE_CACHE【状态标记】 ---- 从磁盘中获取缓存的资源数据【作用】 — ResourceCacheGenerator【执行器】

Stage.DATA_CACHE【状态标记】 ---- 从磁盘中获取缓存的源数据【作用】 — DataCacheGenerator【执行器】

Stage.SOURCE【状态标记】 — 一次新的请求任务 — SourceGenerator【执行器】

因为这里我们没有配置缓存,那么直接看 SourceGenerator
在这里插入图片描述

  @Override
  public boolean startNext() {
		...
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      //获取一个 ModelLoad 加载器
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        //使用加载器中的 fetcher 根据优先级加载数据
        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);
            }
          }
        });
      }
    }
    return started;
  }

helper.getLoadData() 获取的是一个什么样的加载器,我们可以先猜一下,因为没有配置任何缓存,所以可以猜得到是 http 请求了,那么是不是猜测的那样的,我们一起来验证下。

List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear(); 
      //从 Glide 注册的 Model 来获取加载器(注册是在 Glide 初始化的时候通过 registry
       // .append()添加的)
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
     
      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;
  }

首先拿到一个加载器的容器,加载器是在 Glide 初始化的时候 通过 Registry.append() 添加的,这里我们以网络链接举例的。所以,ModelLoad 的实现类是 HttpGlideUrlLoader 加载器,我们看下它的具体实现:
在这里插入图片描述

  @Override
  public LoadData<InputStream> buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    // 看这里,TMD 终于看见Glide 网络加载器了
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }

看到是返回的一个HttpUrlFetcher 给加载器。加载器我们拿到了,现在开始加载,返回到刚刚的源码,请看下面:

  @Override
  public boolean startNext() {
  // ... 
    while (!started && hasNextModelLoader()) {
      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;
  }
  
  private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(...);
  }
  
  @Override
  public void loadData(...) {
  	//...
     //http 请求,返回一个 InputStream 输入流
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      //将 InputStream 以回调形式回调出去
      callback.onDataReady(result);
   	//...
  }
  private InputStream loadDataWithRedirects(...) {
   // ...
    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    urlConnection.setInstanceFollowRedirects(false);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
    stream = urlConnection.getInputStream();
    // ...
  }

至此,终于找到网络请求了,这里是 HttpURLConnection 作为 Glide 底层成网络请求的。请求成功之后直接返回的是一个输入流,最后会通过 callback.onDataReady(result); 回调到 DecodeJob onDataFetcherReady 函数中。同学们我们跟下回调,回调到 SourceGenerator
在这里插入图片描述

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.loadData方法重写了onDataReady,所以有继续调用onDataReadyInternal

  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 --》onDataFetcherRead
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }
 	  @Override
      public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
          DataSource dataSource, Key attemptedKey) {
        this.currentSourceKey = sourceKey; //当前返回数据的 key
        this.currentData = data; //返回的数据
        this.currentFetcher = fetcher; //返回的数据执行器,这里可以理解为 HttpUrlFetcher
        this.currentDataSource = dataSource; //数据来源 url
        this.currentAttemptingKey = attemptedKey;
        if (Thread.currentThread() != currentThread) {
          runReason = RunReason.DECODE_DATA;
          callback.reschedule(this);
        } else {
          GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            //解析返回回来的数据
            decodeFromRetrievedData();
          } finally {
            GlideTrace.endSection();
          }
        }
      } 

  //解析返回的数据
  private void decodeFromRetrievedData() {
    Resource<R> resource = null;
    try {
      // 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream ,  currentDataSource
      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);

    stage = Stage.ENCODE;
    try {
      //这里就是将资源磁盘缓存
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
     ...
    }
	//完成
    onEncodeComplete();
  }

  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    // 在 DecodeJob 的构建中, 我们知道这个 Callback 是 EngineJob
    callback.onResourceReady(resource, dataSource);
  }
}

可以看到上面的 DecodeJob.decodeFromRetrievedData 中主要做了三个处理:

第一个处理:解析返回回来的资源。

第二个处理:拿到解析的资源,如果配置了本地缓存,就缓存到磁盘。

第三个处理:通知上层资源准备就绪,可以使用了。

同学们我们直接看 EngineJob 的 onResourceReady 回调函数:

  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }

void notifyCallbacksOfResult() {
  // ...
	//回调上层 Engine 任务完成了
    engineJobListener.onEngineJobComplete(this, localKey, localResource);

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

通过上面 EngineJob 的 onResourceReady 回调函数 主要做了 两个处理:

? 第一个处理:通知上层任务完成。

? 第二个处理:回调 ImageViewTarget 用于展示数据

private class CallResourceReady implements Runnable {

    private final ResourceCallback cb;

    CallResourceReady(ResourceCallback cb) {
      this.cb = cb;
    }

    @Override
    public void run() {
      synchronized (EngineJob.this) {
        if (cbs.contains(cb)) {
         ...
          //返回准备好的资源
          callCallbackOnResourceReady(cb);
          removeCallback(cb);
        }
        decrementPendingCallbacks();
      }
    }
  }
  @Synthetic
  synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      //回调给 SingleRequest
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }
  @Override
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    // ...
    //当资源准备好的时候
      onResourceReady((Resource<R>) resource, (R) received, dataSource);
      // ...
  }

  private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    // ...
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
        //回调给目标 ImageViewTarget 资源准备好了
        target.onResourceReady(result, animation);
      }
   
    notifyLoadSuccess();
  }
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
    implements Transition.ViewAdapter {
  @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) {
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }

  protected abstract void setResource(@Nullable Z resource);
}

在最开始构建的时候,我们知道只有调用 asBitmap 的时候实现类是 BitmapImageViewTarget,在这里的测试,并没有调用这个函数,所以它的实现类是 DrawableImageViewTarget,具体看下它内部实现:

public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {

  public DrawableImageViewTarget(ImageView view) {
    super(view);
  }

  /** @deprecated Use {@link #waitForLayout()} instead. */
  // Public API.
  @SuppressWarnings({"unused", "deprecation"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }

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

这里看到抽象类中调用了 setResource ,子类实现并调用了 view.setImageDrawable(resource); 图片现在算是真正的显示出来了

是否已经淹死在源码里了

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:21:45  更:2022-03-11 22:22:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:53:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码