美文网首页ITBOXAndroid coder进阶安卓开发笔记
Glide 源码学习,了解 Glide 图片加载原理

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

作者: 看我眼前007 | 来源:发表于2017-11-23 17:10 被阅读3582次
    基于 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的执行流程

    相关文章

      网友评论

      本文标题:Glide 源码学习,了解 Glide 图片加载原理

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