Glide源码分析


不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!

Glide的源码分析

面试题:为什么不能在子线程调用with方法?

答:因为在子线程调用,不会产生一个空白的Fragment和Activity进行生命周期的绑定;可能导致Activity销毁了,图片请求资源仍然存在,导致内存泄漏。

面试题:为什么使用Glide框架需要网络请求权限?

答:如果活动缓存和内存缓存中都没有数据可以返回,并且本地磁盘缓存中也没有,就只能执行最后一个方法,通过网络请求去返回数据,因此在无缓存的情况下,需要进行异步网络请求数据。

Glide的使用

使用Glide框架非常简单,最基本的就一句话。

Glide.with(MainActivity.this).load(url).into(ImageView);

With方法

  • With方法最主要的就是调用get方法,返回一个RequestManager对象。
  • 因为Activity最终继承FragmentActivity,所以传入的参数是FragmentActivity

在get方法中,有这么一句。

public RequestManager get(FragmentActivity activity) {
    //通过判断是否在子线程
    if (Util.isOnBackgroundThread()) {
        //位于子线程,直接和Application的context绑定
        //就不能和Activity生命周期绑定
      return get(activity.getApplicationContext());
    } else {
        //位于主线程
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
        //使用一个空白的Fragment和Activity进行生命周期绑定
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

load方法

  • 调用RequestManagerload方法
  • 返回一个RequestBuilder对象

into方法(重点)

into方法的时序图
在这里插入图片描述

  • 调用RequestBuilderinto方法
public Target<TranscodeType> into(ImageView view) {
    //确定在主线程执行UI操作
    Util.assertMainThread();
    //确定控件存在
    Preconditions.checkNotNull(view);

    //是否设置了scaleType属性
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
          //克隆,原型设计模式
        requestOptions = requestOptions.clone();
      }
        //通过scaleType属性判断走哪条路径
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
              //不设置scaleType属性的默认路径
          requestOptions.optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions.optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    //最终进入的方法
    //这里确定返回的target对象为ImageViewTarget
    //铺垫,伏笔
    return into(context.buildImageViewTarget(view, transcodeClass));
  }
  • into里面的子线方法——buildImageViewTarget

  • 进入buildImageViewTarget方法

    public <X> Target<X> buildImageViewTarget(ImageView imageView, Class<X> transcodeClass) {
      return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
    }
    

通过buildImageViewTarget的源码可以看出,通过工厂模式,进行Target对象的实例化。

  • 继续调用上面的into方法
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    //上一个请求
    Request previous = target.getRequest();
    //上一个请求没有结束
    if (previous != null) {
        //将请求结束,确保下一个请求执行前,所有请求结束
      requestManager.clear(target);
    }
    //lock()保证线程安全
    requestOptions.lock();
    //得到当前请求,通过buildRequest一层层调用可知,最终返回的是singleRequest对象
    //铺垫,伏笔
    Request request = buildRequest(target);
    //将请求和Target绑定
    target.setRequest(request);
    //进入这个方法,执行请求
    requestManager.track(target, request);
    //最终返回这个Target对象,即无论调用路径多长
    //最终都会回到这个target对象
    return target;
  }

铺垫:通过buildRequest可以知道返回的RequestSingleRequest

  • 调用RequestManagertrace方法
void track(Target<?> target, Request request) {
    targetTracker.track(target);
    //执行这个Request请求
    requestTracker.runRequest(request);
  }
  • 执行请求,调用RequestTrackerrunRequest方法
public void runRequest(Request request) {
    //运行请求,Set类型
    //private final Set<Request> requests
    requests.add(request);
    if (!isPaused) {
        //未暂停,开始执行
      request.begin();
    } else {
        //等待请求,List类型
        // private final List<Request> pendingRequests = new ArrayList<>();
      pendingRequests.add(request);
    }
  }

由源码可知,两个请求的类型不同,因为他们的状态不同,一个等待,一个执行。

  • 调用Requestbegin方法
package com.bumptech.glide.request;

/**
 * A request that loads a resource for an {@link com.bumptech.glide.request.target.Target}.
 */
public interface Request {

  /**
   * Starts an asynchronous load.
   */
  void begin();
  ...
}

通过源码发现,Request为一个接口,那么它的实现类是什么呢?

上述铺垫的buildRequest方法告诉我们,它的实现类是SingleRequest。

  • 调用SingleRequestbegin方法
 public void begin() {
    ... 
    status = Status.WAITING_FOR_SIZE;
     //如果Target尺寸和这个一致
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        //准备
      onSizeReady(overrideWidth, overrideHeight);
    } else {
        //获得target尺寸
      target.getSize(this);
    }
    ...
  }
  • 调用SingleRequestonSizeReady方法
 public void onSizeReady(int width, int height) {
    ...
     //设置正在运行
    status = Status.RUNNING;
    ...
        //调用load方法,加载引擎
    loadStatus = engine.load(
        glideContext,
        model,
        requestOptions.getSignature(),
        this.width,
        this.height,
        requestOptions.getResourceClass(),
        transcodeClass,
        priority,
        requestOptions.getDiskCacheStrategy(),
        requestOptions.getTransformations(),
        requestOptions.isTransformationRequired(),
        requestOptions.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
   ...
  }
  • 调用Engineload方法
public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
   ...
       //key表示引擎的唯一索引
       //通过工厂模式创建得到
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    //得到引擎资源
    //先从内存缓存中找
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    //缓存中有
    if (cached != null) {
        //直接准备资源
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    //活动缓存,面向用户
    //逻辑和内存缓存一致
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    //看看EngineJob是否存在在磁盘缓存中
    EngineJob<?> current = jobs.get(key);
    //存在则执行下列操作
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    //不存在,通过工厂模式创建
    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
    //DecodeJob同理
    DecodeJob<R> decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        onlyRetrieveFromCache,
        options,
        engineJob);
    //jobs里面没有,加入磁盘中
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    //将decodeJob放入engineJob中
    //开启引擎
    engineJob.start(decodeJob);
    ...
    return new LoadStatus(cb, engineJob);
  }
  • 调用EngineJobstart方法
public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    //最终执行
    executor.execute(decodeJob);
  }
  • 调用GlideExecutorexecute方法(线程池管理执行任务)
@Override
  public void execute(Runnable command) {
    if (executeSynchronously) {
      command.run();
    } else {
      super.execute(command);
    }
  }

execute方法传入的参数是DecodeJob,在这个方法可知,里面的参数是Runnable类型的。然后执行Runnablerun方法,发现Runnable是个接口,那么它的具体实现类是什么呢?就是它传入的参数了,是DecodeJob

  • 调用DecodeJobrun方法
public void run() {
    try {
        //取消执行
      if (isCancelled) {
        notifyFailed();
        return;
      }
        //不取消就执行这个方法
      runWrapped();
    } catch (RuntimeException e) {
     ...
    }
  }
  • 执行DecodeJobrunWrapped方法
 private void runWrapped() {
     switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
             //铺垫,是否配置缓存策略
             //默认返回source
        currentGenerator = getNextGenerator();
             //执行
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
             //执行
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

getNextGenerator方法中证明了下面的实现类是ResourceCacheGenerator,DataCacheGenerator, SourceGenerator(默认返回)中的。

  • 执行DecodeJobrunGenerators方法
private void runGenerators() {
    ...
    while (!isCancelled && currentGenerator != null
           //当前Generator的下一个方法
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
   ...
  }
  • 调用DataFetcherGenerator的startNext方法

发现又是一个接口,因为只有SourceGenerator中有这个方法,所以实现类SourceGenerator。

  • 实现类实现startNext方法
public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
        //返回loadData
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
          //去获取数据,返回
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }
  • 调用loadData.fetcher.loadData,发现又是个接口,这里找不到实现类,那么就要看这个对象如何得到的。

    glide有个注册机制,注册很多的组件,会把HttpGlideUrlLoader注册进来,进行网络请求。

    loadData = helper.getLoadData()方法中有

    LoadData<?> current =
        modelLoader.buildLoadData(model, width, height, options);
    

通过注册机制可知:LoadData<?> current = HttpGlideUrlLoader;

  • 调用里面的buildLoadData方法,发现是接口方法,然后找到实现类HttpGlideUrlLoader

  • 调用HttpGlideUrlLoaderbuildLoadData方法
    在这里插入图片描述

  • 到HttpUrlFetcher类,进行网络请求

  • 继续loadData,最后到loadDataWithRedirects方法,返回InputSream,得到数据流InputStream

public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
        //得到数据Stream
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
        //得到的数据回调
      callback.onDataReady(result);
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
    } finally {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }
private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
    ...
    //真正的网络请求,底层Socket
    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);

    urlConnection.connect();
   
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    ...
}
  • 得到的数据回调,调用onDataReady发现又是接口,数据回调到DataCacheGenerator缓存
  • 继续回调,又是接口,到DecodeJob
public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

后面的InputStream回调之后,会在StreamBitmapDecoder中进行采样压缩,变成bitmap,然后返回到Enigne中保存在活动缓存中,最后最后,回调OnResourceReady方法,最后到ImageViewTargetOnResourceReady方法,再通过setDrawable等方法,显示图片。

总结流程(简化)

  1. 构建Glide
  2. 给每一个RequestManager绑定一个空白的Fragment管理生命周期
  3. 构建Request
  4. 请求之前,判断两级缓存(活动缓存和内存缓存)中是否有需要的数据
  5. 都没有,建立一个新的异步任务
  6. 在本地的磁盘缓存中寻找
  7. 若没有,则进行网络请求返回一个输入流InputStream。
  8. 将InputStream采样压缩处理变为Bitmap,防止出现oom
  9. 后将Bitmap转换为drawable
  10. 传输到终点ImageViewTarget中,并在其子类DrawableImageViewTarget中显示图片。

生命周期绑定的作用

比如当前有100个请求,10个请求正在处理,90个请求正在等待。若这10个请求执行完毕,Activity或者Fragment被销毁,则其他的未执行的请求也一同回收,不会再发送请求。即将所有的资源进行关联,同步回收,避免出现内存泄漏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值