Glide 源码学习,了解 Glide 图片加载原理

基于 Gilde 4.3.1
Glide 是我非常喜欢使用的图片加载框架,这篇文章讲从源码的角度剖析 Glide 框架。
从而得知 Glide 为我们做了哪些工作。

Glide 的使用参考文档

    ImageView imageView = findViewById(R.id.test);
    ImgurGlide.with(getApplicationContext())
            .load(imageUrl)
            .into(imageView);

Glide 使用起来特别方便,一条链式调用就可以把图片下载并显示到 ImageView 上。
其中 ImgurGlide 是我们自定义的一个 AppGlideModule

@GlideModule(glideName = "ImgurGlide")
public class ImgurGlideModule extends AppGlideModule {
    // Intentionally Empty.
}

ImgurGlide 的生成,使用了 APT(Annotation Processing Tool)技术,这里先不做讲述。ImgurGlide 的每个方法都是包裹了 Glide 静态对象去实现。

逐步分析

Glide.with(……)

Glide.with() 有下面几种实现方式。

1. Glide.with(Context context)
2. Glide.with(Activity activity)
3. Glide.with(FragmentActivity activity)
4. Glide.with(android.app.Fragment fragment)
5. Glide.with(View view)

所以的方法实现也是很类似,都是调用同一个方法

public static RequestManager with(Fragment fragment) {
  return getRetriever(fragment.getActivity()).get(fragment);
}

再看一下 getRetriever() 方法

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  ……
  省略一些判空检查
  ——
  return Glide.get(context).getRequestManagerRetriever();
}

其中 Glide.get(context) 主要用来初始化 Glide 的全局单利对象,以及一些配置。

getRequestManagerRetriever() 则是返回 Glide 对象的 requestManagerRetriever 对象。

然后看一下 requestManagerRetriever.get() 方法

public RequestManager get(Context context) {
  if (context == null) {
    throw new IllegalArgumentException("You cannot start a load on a null Context");
  } else if (Util.isOnMainThread() && !(context instanceof Application)) {
    if (context instanceof FragmentActivity) {
      return get((FragmentActivity) context);
    } else if (context instanceof Activity) {
      return get((Activity) context);
    } else if (context instanceof ContextWrapper) {
      return get(((ContextWrapper) context).getBaseContext());
    }
  }

  return getApplicationManager(context);
}

get() 方法会根据传入的 context 对象和当前线程,创建不同的 RequestManager 实例

1. 非 UI 线程,返回 applicationManager 对象,能感知 Application 生命周期。
2. UI 线程,如果 context 是 Activity 、FragmentActivity 
   则会创建一个能感知对应 Activity 的 RequestManager。
3. UI 线程,如果 Context 是 Fragment、android.support.v4.app.Fragment 
   则会创建一个能感知对应 Fragment 生命周期 的 RequestManager。

这里反复提到了一个 感知生命 xx 周期,也是 Glide 的一个特性。

Glide 在加载资源的时候,如果是在 Activity、Fragment 这一类有生命周期的组件上进行。
当 Activity、Fragment 等组件进入不可见,或者已经销毁的时候,Glide 会停止加载资源。
Application 的生命周期贯穿整个应用,所以 applicationManager 只有在应用程序关闭的时候终止加载。

所以尽量不要在非 UI 线程使用 Glide 加载图片,尽量使用 Activity、Fragment 等带有生命周期的组件配合 Glide 使用。

Glide 如何获得 Activity、Fragment 生命周期回调

在 各种 requestManagerRetriever.get() 方法中如果传入的是带有生命周期的组件,并且在 UI 线程,会执行以下几个方法端

  // FragmentActivity
  assertNotDestroyed(activity);
  FragmentManager fm = activity.getSupportFragmentManager();
  return supportFragmentGet(activity, fm, null /*parentHint*/);
  
  //android.support.v4.app.Fragment
  FragmentManager fm = fragment.getChildFragmentManager();
  return supportFragmentGet(fragment.getActivity(), fm, fragment);
  
  //Activity
  assertNotDestroyed(activity);
  android.app.FragmentManager fm = activity.getFragmentManager();
  return fragmentGet(activity, fm, null /*parentHint*/);
  
  //android.app.Fragment
  android.app.FragmentManager fm = fragment.getChildFragmentManager();
  return fragmentGet(fragment.getActivity(), fm, fragment);
  1. 如果是 Activity ,先获取 FragmentManager ,如果是 Fragment 则先获取 ChildFragmentManager。
  2. 如果是 support 包下面的 Activity 、Fragment 调用 supportFragmentGet,否则调用 fragmentGet。

fragmentGet() 和 supportFragmentGet() 方法大致类似,选取一个分析一下。

private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
    android.app.Fragment parentHint) {
  RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
  RequestManager requestManager = current.getRequestManager();
  if (requestManager == null) {
    // TODO(b/27524013): Factor out this Glide.get() call.
    Glide glide = Glide.get(context);
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

上面这段代码做了两个功能

 1. 创建一个 RequestManagerFragment。
 2. 创建一个 RequestManager。

先看一下 getRequestManagerFragment

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(
    final android.app.FragmentManager fm, android.app.Fragment parentHint) {
  RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  if (current == null) {
    current = pendingRequestManagerFragments.get(fm);
    if (current == null) {
      current = new RequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      pendingRequestManagerFragments.put(fm, current);
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

这是是 Glide 设计中比较一个巧妙的地方

创建一个透明的 RequestManagerFragment 加入到FragmentManager 之中
通过添加的这个 Fragment 感知 Activity 、Fragment 的生命周期。

Fragment 源码学习,从源码理解 Fragment 生命周期中已经说明,添加到 Activity的 Fragment 会跟随Activity的生命周期。

Fragment的 childFragment 则会通过 ChildFragmentManager 和 Fragment 保持生命周期一致。

这里说一个细节

刚开始看这段代码时,看到 handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();

    ……
    case ID_REMOVE_FRAGMENT_MANAGER:
    android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
    key = fm;
    removed = pendingRequestManagerFragments.remove(fm);
    ……
以为 Glide 添加了一个 Fragment 到 FragmentManager 中,然后又删除了。为此困惑了好久。
在 Glide 的 github 里 issue#2289 才明白。
   
   Glide 在添加 Fragment 到 FragmentManger 后,
   再从 pendingRequestManagerFragments 中删除 FragmentManager 。
   并不是删除 Fragment。

在 RequestManagerFragment 中可以看到以下代码

@Override
public void onStart() {
  super.onStart();
  lifecycle.onStart();
}

@Override
public void onStop() {
  super.onStop();
  lifecycle.onStop();
}

@Override
public void onDestroy() {
  super.onDestroy();
  lifecycle.onDestroy();
  unregisterFragmentWithRoot();
}

专业就可以通过 RequestManagerFragment 把 Activity 的生命周期通过 lifecycle 传递给在 lifecycle 注册的 LifecycleListener。

RequestManager.load(url)

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

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

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

public RequestBuilder<TranscodeType> load(@Nullable Object model) {
  return loadGeneric(model);
}

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  this.model = model;
  isModelSet = true;
  return this;
}

以上就是 RequestBuilder.load(url) 的相关代码,发现并没有什么特殊之处。 只是创建了一个 RequestBuilder 。

RequestBuilder.into(view)

into() 方法调用起来十分方便,只要传递一个 ImageView ,Glide 就会自动下载图片,并且显示到 ImageView 上。这看似十分简单的一步,也是 Glide 最负责的调用。

public Target<TranscodeType> into(ImageView view) {
  
  RequestOptions requestOptions = this.requestOptions;
  ……
  
  return into(
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions);
}

跟踪一下 glideContext.buildImageViewTarget(view, transcodeClass) 会发现这里返回的是一个DrawableImageViewTarget

into(ImageView view) 把 requestOptions 和 DrawableImageViewTarget 传入

private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    RequestOptions options) {
  ……
  Request request = buildRequest(target, targetListener, options);

  Request previous = target.getRequest();
  ……
  requestManager.clear(target);
  target.setRequest(request);
  requestManager.track(target, request);

  return target;
}

下一步跟踪到 requestManager.track(target, request)

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

public void runRequest(Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    pendingRequests.add(request);
  }
}  

isPaused 变量

1. 如果此时 GlideRequests 的 Lifecycle 为 ApplicationLifecycle,只要应用存活
   isPaused 为 false ,直接执行 request.begin()
2. 如果 GlideRequests 的 Lifecycle 是观测 Fragment 或者 Activity
   isPaused 为true ,不会立即执行 request.begin()
   当 Fragment 或者 Activity 显示到前台时通过遍历 requests 数组执行 request.begin()

所以执行网络请求下载图片的操作在 request.begin() 之中。

回到 into(ImageView view) 方法的

Request request = buildRequest(target, targetListener, options)

经过层层包裹我们可以找到一下路线,发现最后返回的是 SingleRequest

buildRequest >> buildRequestRecursive >> buildThumbnailRequestRecursive

>> obtainRequest >> SingleRequest

创建 SingleRequest 的过程比较复杂,牵扯到缩略图、错误处理之类的逻辑,大致都是上面那条路径。

然后就看一下 SingleRequest.begin()

@Override
public void begin() {
  ……
  省略一些其他分支
  ……
  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    onSizeReady(overrideWidth, overrideHeight);
  } else {
    target.getSize(this);
  }
  ……
  ……
}

begin() 方法很长,我们剔除了一些异常处理,直接看最核心的方法。

如果我给 Glide 设置了 override() 则直接调用 onSizeReady(overrideWidth, overrideHeight)

否则会调用 target.getSize(this) 让 ImageView 计算自己的尺寸。

glideContext.buildImageViewTarget(view, transcodeClass) 创建一个 DrawableImageViewTarget

先看一些 DrawableImageViewTarget 类的继承关系图


gilde_01.png

这个类图关系中 SizeDeterminer.getSize(SizeReadyCallback cb)就是计算 ImageView 尺寸

void getSize(SizeReadyCallback cb) {
  int currentWidth = getTargetWidth();
  int currentHeight = getTargetHeight();
  if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
    cb.onSizeReady(currentWidth, currentHeight);
    return;
  }

  // We want to notify callbacks in the order they were added and we only expect one or two
  // callbacks to be added a time, so a List is a reasonable choice.
  if (!cbs.contains(cb)) {
    cbs.add(cb);
  }
  if (layoutListener == null) {
    ViewTreeObserver observer = view.getViewTreeObserver();
    layoutListener = new SizeDeterminerLayoutListener(this);
    observer.addOnPreDrawListener(layoutListener);
  }
}

其中 getTargetWidth() 和 getTargetHeight()是用来计算 View 尺寸的,在 View 尺寸法伤改变的时候时候通过 SizeDeterminerLayoutListener 通知 SizeReadyCallback View 尺寸发生改变。

流程最终都会执行 SingleRequest.onSizeReady(width, height) 方法

@Override
public void onSizeReady(int width, int height) {
  ……
  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);
  ……
}

看到一个新的对象 Engine 从字面意思上可以猜测好像是用来加载图片用的,查看 engine.load()

public <R> LoadStatus load(……) {
  ……
  如果资源已经缓存,直接调用 onResourceReady
  ……
  cb.onResourceReady(active, DataSource.MEMORY_CACHE);
  ……
  EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
      useUnlimitedSourceExecutorPool, useAnimationPool);
  DecodeJob<R> decodeJob = decodeJobFactory.build(……);
  jobs.put(key, engineJob);
  engineJob.addCallback(cb);
  engineJob.start(decodeJob);
  ……
  return new LoadStatus(cb, engineJob);
}

load() 方法很长,上面只保留和核心的内容。

EngineJob 和 DecodeJob 是用来加载网络资源的,如果资源已经存在,不会重复加载。

先看下 cb.onResourceReady(active, DataSource.MEMORY_CACHE)

这里的 cb 就是 SingleRequest

public void onResourceReady(Resource<?> resource, DataSource dataSource) {
  ……
  ……
  onResourceReady((Resource<R>) resource, (R) received, dataSource);
}

private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
  ……
  try {
    if (……) {
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
      target.onResourceReady(result, animation);
    }
  } finally {
    isCallingCallbacks = false;
  }

  notifyLoadSuccess();
}

流程会跳转到 target.onResourceReady(result, animation) ,target 就是 DrawableImageViewTarget

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

直接看 setResourceInternal(resource)

private void setResourceInternal(@Nullable Z resource) {
  maybeUpdateAnimatable(resource);
  setResource(resource);
}

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

以上终于看到 view.setImageDrawable(resource) 。

以上大致就是 ImgurGlide.with(getApplicationContext()).load(imageUrl).into(imageView) 的大致流程,先总计如下。

Glide 从网络下载图片的流程更复杂,后面重点讲。

gilde_02.png

Glide 网络加载图片

Glide 网络加载图片比较负责,找了很久才找到做网络请求的部分。这里单独拉出来讲。
先回到 load() 方法。

public <R> LoadStatus load(……) {
  ……
  如果资源已经缓存,直接调用 onResourceReady
  ……
  cb.onResourceReady(active, DataSource.MEMORY_CACHE);
  ……
  EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
      useUnlimitedSourceExecutorPool, useAnimationPool);
  DecodeJob<R> decodeJob = decodeJobFactory.build(……);
  jobs.put(key, engineJob);
  engineJob.addCallback(cb);
  engineJob.start(decodeJob);
  ……
  return new LoadStatus(cb, engineJob);
}

看一下 engineJob.start(decodeJob)

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

这里看到了线程池操作 这里有两个线程池,分别对象两种缓存方式。有兴趣可以去看下这两种线程池的配置

Engine 的初始化在 GlideBuilder.build(Context context)

    ……
    if (engine == null) {
      engine =
      new Engine(
      memoryCache,
      diskCacheFactory,
      diskCacheExecutor,
      sourceExecutor,
      GlideExecutor.newUnlimitedSourceExecutor(),
      GlideExecutor.newAnimationExecutor());
   }
   ……

那 DecodeJob 肯定是负责加载图片的了,先看 DecodeJob.run()

public void run() {
  ……
  try {
    if (isCancelled) {
      notifyFailed();
      return;
    }
    runWrapped();
  }
  ……
}

正常情况下会执行

private void runWrapped() {
   switch (runReason) {
    case INITIALIZE:
      stage = getNextStage(Stage.INITIALIZE);
      currentGenerator = getNextGenerator();
      runGenerators();
      break;
    case SWITCH_TO_SOURCE_SERVICE:
      runGenerators();
      break;
    case DECODE_DATA:
      decodeFromRetrievedData();
      break;
    default:
      throw new IllegalStateException("Unrecognized run reason: " + runReason);
  }
}

这里可以看到有很多分析,通过 Debug 可以知道这里走 INITIALIZE 。至于其他情况,等着以后去研究吧。

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

因为我们传入的是一个 Url 地址,会走 SOURCE 分支,返回一个 SourceGenerator。

接着执行 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 循环条件里面的 currentGenerator.startNext()),即 SourceGenerator

@Override
public boolean startNext() {
  ……
  while (!started && hasNextModelLoader()) {
    loadData = helper.getLoadData().get(loadDataListIndex++);
    if (……) {
      started = true;
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  return started;
}

这又出现了新的对象 loadData 并且执行 loadData.fetcher.loadData(……)

看起来特别想是加载网络图片操作,但是这部分代码有点不好理解。

loadData 是什么?
fetcher 又是什么?
搞不清池这两个对象是什么,根本没法继续跟进了!!!
寻找 loadData

根据 while 那段代码判断 helper.getLoadData() 似乎返回了不止一个 loadData ,所以需要循环遍历每一个 loadData 找到能执行 loadData.fetcher.loadData(helper.getPriority(), this)的对象。

List<LoadData<?>> getLoadData() {
  if (!isLoadDataSet) {
    isLoadDataSet = true;
    loadData.clear();
    List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
    int size = modelLoaders.size();
    for (int i = 0; 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;
}

这里看出 DecodeHelper 对象遍历 glideContext 的 Registry 对象,寻找匹配 model 的 ModelLoader

然后执行 modelLoader.buildLoadData(model, width, height, options) 创建 LoadData 并添加到 List 返回。

于是又引入两个问题

ModelLoader 是啥玩意?
modelLoader.buildLoadData() 做啥玩意?

啊~~~~~ 好头疼!!!

继续跟代码

 public <Model> List<ModelLoader<Model, ?>> getModelLoaders(Model model) {
   List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
   if (result.isEmpty()) {
     throw new NoModelLoaderAvailableException(model);
   }
   return result;
 }
 
public synchronized <A> List<ModelLoader<A, ?>> getModelLoaders(A model) {
  List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
  int size = modelLoaders.size();
  List<ModelLoader<A, ?>> filteredLoaders = new ArrayList<>(size);
  for (int i = 0; i < size; i++) {
    ModelLoader<A, ?> loader = modelLoaders.get(i);
    if (loader.handles(model)) {
      filteredLoaders.add(loader);
    }
  }
  return filteredLoaders;
}

private <A> List<ModelLoader<A, ?>> getModelLoadersForClass(Class<A> modelClass) {
   List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
   if (loaders == null) {
     loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
     cache.put(modelClass, loaders);
   }
   return loaders;
 }

以上方法似乎还是看不出什么,在这里纠结很久。最后发现在 Glide 构造方法中有以下代码

Glide(……) {
  ……
  registry
      .append(ByteBuffer.class, new ByteBufferEncoder())
      .……
      这里省略很多  append
       ……
      .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
      .append(String.class, InputStream.class, new StringLoader.StreamFactory())
      ……
      这里省略很多  append
      ……
}

append() 方法

public <Model, Data> Registry append(Class<Model> modelClass, Class<Data> dataClass,
    ModelLoaderFactory<Model, Data> factory) {
  modelLoaderRegistry.append(modelClass, dataClass, factory);
  return this;
}

 public synchronized <Model, Data> void append(Class<Model> modelClass, Class<Data> dataClass,
     ModelLoaderFactory<Model, Data> factory) {
   multiModelLoaderFactory.append(modelClass, dataClass, factory);
   cache.clear();
 }

到这里我们终于看到了一点阳光

Glide 注册了很多 modelLoader 
这些 modelLoader 就是加载各种资源用的

我们使用的字符串表示 URL ,应该属于 String 类型

.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())

处理 String 类型的有三个,但是我们是网络下载图片所以可以排除第三个。

每一个 ModelLoader 对象都有一个

public boolean handles(String url) {
    ……
}

DataUrlLoader 的 handles 只接受 "data:image" 开头的字符,所以只剩下 StringLoader。

这里直接说出了结果,具体每一步的调用可以按照上面思路,配合单步调试了解详情

然后看下 StreamFactory 和 StringLoader.buildLoadData()

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

   @Override
   public ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {
     return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
   }

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

 @Override
public LoadData<Data> buildLoadData(String model, int width, int height,
    Options options) {
  Uri uri = parseUri(model);
  return uri == null ? null : uriLoader.buildLoadData(uri, width, height, options);
}

可以看到 StringLoader.buildLoadData() 又代理给了处理 <Uri.class, InputStream.class> 的 ModelLoader

然后在 Glide 的一堆 append 中找到对应的 UrlUriLoader.StreamFactory()

再次发现,又代理给了 <GlideUrl.class, InputStream.class>,于是我们终于找到 HttpGlideUrlLoader 并且再没有代理到其他 ModelLoader

Glide 的里面注册很多 ModelLoader 只是一个包裹器,有具体操作的就几种 ModelLoader 
HttpGlideUrlLoader 是其中一个。

HttpGlideUrlLoader 的 buildLoadData 返回了我们要找的 LoadData

public LoadData<InputStream> buildLoadData(GlideUrl model, int width, int height,
    Options options) {
  ……
  return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
寻找 fetcher

找到 LoadData 的同时,我们也找到了 fetcher 即 HttpUrlFetcher

看名字我们就能知道,这个类肯定和 Http 有关。loadData.fetcher.loadData(helper.getPriority(), this) 的具体实现方法也跟着找到了

  @Override
  public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    final InputStream result;
    try {
      result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/,
          glideUrl.getHeaders());
    } 
    ……
    callback.onDataReady(result);
  }
  
  
  private InputStream loadDataWithRedirects(……) throws IOException {
  ……
  if (statusCode / 100 == 2) {
    return getStreamForSuccessfulRequest(urlConnection);
  } else if (statusCode / 100 == 3) {
    ……
    处理重定向
    ……
  } 
  ……
  异常处理
  ……
}

 private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
     throws IOException {
     ……
     stream = urlConnection.getInputStream();
   }
   return stream;
 }

以上这些代码不做解释了,就是发起网络请求,接收返回的数据流。

loadData() 方法还有一句

callback.onDataReady(result);

这里的 callback 就是 SourceGenerator,所以看 SourceGenerator.onDataReady()

public void onDataReady(Object data) {
  DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
  if (……) {
    dataToCache = data;
    cb.reschedule();
  } else {
    cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
        loadData.fetcher.getDataSource(), originalKey);
  }
}

如果执行成功了会执行 cb.reschedule() 或者 cb.onDataFetcherReady() 这里的 cb 是 DecodeJob

public void reschedule() {
  runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
  callback.reschedule(this);
}

public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
    DataSource dataSource, Key attemptedKey) {
  if (Thread.currentThread() != currentThread) {
    runReason = RunReason.DECODE_DATA;
    callback.reschedule(this);
  } else {
    TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
    try {
      decodeFromRetrievedData();
    } finally {
      TraceCompat.endSection();
    }
  }
}

callback.reschedule(this) 其实就是 EngineJob..reschedule()

public void reschedule(DecodeJob<?> job) {
  // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
  // up.
  getActiveSourceExecutor().execute(job);
}  

用来再次执行 DecodeJob ,会改变 DecodeJob 的 runReason。这些任务调度比较复杂,经过一些列 debug 得出结果如下

 经过一些列的 reschedule 如果图片下面成功会执行 decodeFromRetrievedData()
 
 decodeFromRetrievedData 
 >> notifyEncodeAndRelease 
 >> notifyComplete 
 >> callback.onResourceReady

最终调用 EngineJob.onResourceReady()

public void onResourceReady(Resource<R> resource, DataSource dataSource) {
  this.resource = resource;
  this.dataSource = dataSource;
  MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}

public boolean handleMessage(Message message) {
     EngineJob<?> job = (EngineJob<?>) message.obj;
     switch (message.what) {
       case MSG_COMPLETE:
         job.handleResultOnMainThread();
         break;
       ……
     }
     return true;
   }
 }
 
void handleResultOnMainThread() {
  ……
  for (ResourceCallback cb : cbs) {
    if (!isInIgnoredCallbacks(cb)) {
      engineResource.acquire();
      cb.onResourceReady(engineResource, dataSource);
    }
  }
  ……
  engineResource.release();

  release(false /*isRemovedFromQueue*/);
}

handleResultOnMainThread 中的 cb.onResourceReady(engineResource, dataSource) 即通知资源获取成功。这里的 cb 即 SingleRequest 和上一部分内容对接上了。

  public <R> LoadStatus load(……) {
    ……
    ……
    engineJob.addCallback(cb); // 传入 SingleRequest
    engineJob.start(decodeJob);

    ……
  }

总结以上流程如下


gilde_03.png

备注

Glide 还有很多需要探究的知识点,这篇文章写不下了。先写那么多吧。

参考资料

Gilde github 地址

Gilde 参考文档

#2289 Why do you do?

Glide原理之Activity、Fragment生命周期监听(三)

Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容