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閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容