美文网首页Android开发经验谈Android技术知识Android开发
Android 高频面试题解析:Glide流程解析

Android 高频面试题解析:Glide流程解析

作者: Android写到秃 | 来源:发表于2022-04-08 14:49 被阅读0次

    从主流程分析

    Glide最简单的使用:

    Glide
        .with(context)
        .load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png")
        .into(iv)
    
    
    image.png

    Glide加载图片最简单的是三步:

    • Glide.with(context)来获取Glide对象和RequestManager对象并绑定Context生命周期;
    • RequestManager.load(url)获取RequestBuilder对象并绑定图片Url,此时还没有去加载Url地址;
    • RequestBuilder.into(iv)加载图片并且将获取到的图片显示到ImageView中。

    下面跟着三步一步一步来看下具体实现。

    Glide.with(context)

    com.bumptech.glide.Glide#with(Context)
    
    public static RequestManager with(@NonNull Context context) {
      return getRetriever(context).get(context);
    }
    
    private static RequestManagerRetriever getRetriever(@Nullable Context context) {
      return Glide.get(context).getRequestManagerRetriever();
    }
    
    // 获取Glide单例对象
    public static Glide get(@NonNull Context context) {
      if (glide == null) {
        GeneratedAppGlideModule annotationGeneratedModule =
            getAnnotationGeneratedGlideModules(context.getApplicationContext());
        synchronized (Glide.class) {
          if (glide == null) {
            checkAndInitializeGlide(context, annotationGeneratedModule);
          }
        }
      }
      return glide;
    }
    
    

    Glide.with()一共有两大步:

    • getRetriever(context)获取Glide单例对象和RequestManagerRetriever对象;
    • get(context)获取RequestManager对象同时绑定当前Context的生命周期。

    Glide单例创建

    Glide对象的首次创建跟代码是从Glide.get(context)->checkAndInitializeGlide()->initializeGlide()->GlideBuilder#build(),最终通过建造者模式创建Glide对象。

    com.bumptech.glide.GlideBuilder#build
    
    Glide build(@NonNull Context context) {
      if (sourceExecutor == null) {
        sourceExecutor = GlideExecutor.newSourceExecutor();
      }
    
      if (diskCacheExecutor == null) {
        diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
      }
    
      if (animationExecutor == null) {
        animationExecutor = GlideExecutor.newAnimationExecutor();
      }
    
      if (memorySizeCalculator == null) {
        memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
      }
    
      if (connectivityMonitorFactory == null) {
        connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
      }
    
      if (bitmapPool == null) {
        int size = memorySizeCalculator.getBitmapPoolSize();
        if (size > 0) {
          bitmapPool = new LruBitmapPool(size);
        } else {
          bitmapPool = new BitmapPoolAdapter();
        }
      }
    
      if (arrayPool == null) {
        arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
      }
    
      if (memoryCache == null) {
        memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
      }
    
      if (diskCacheFactory == null) {
        diskCacheFactory = new InternalCacheDiskCacheFactory(context);
      }
    
      if (engine == null) {
        engine =
            new Engine(
                memoryCache,
                diskCacheFactory,
                diskCacheExecutor,
                sourceExecutor,
                GlideExecutor.newUnlimitedSourceExecutor(),
                animationExecutor,
                isActiveResourceRetentionAllowed);
      }
    
      if (defaultRequestListeners == null) {
        defaultRequestListeners = Collections.emptyList();
      } else {
        defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
      }
    
      GlideExperiments experiments = glideExperimentsBuilder.build();
      RequestManagerRetriever requestManagerRetriever =
          new RequestManagerRetriever(requestManagerFactory, experiments);
    
      return new Glide(
          context,
          engine,
          memoryCache,
          bitmapPool,
          arrayPool,
          requestManagerRetriever,
          connectivityMonitorFactory,
          logLevel,
          defaultRequestOptionsFactory,
          defaultTransitionOptions,
          defaultRequestListeners,
          experiments);
    }
    
    

    创建Glide对象的同时还创建其它很多的实例,包括缓存执行器SourceExecutorDiskCacheExecutor,加载引擎EngineRequestManagerRetriever等。

    RequestManager创建

    com.bumptech.glide.manager.RequestManagerRetriever#get(Context)
    
    public RequestManager get(@NonNull 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
            // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
            // Context#createPackageContext may return a Context without an Application instance,
            // in which case a ContextWrapper may be used to attach one.
            && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
          return get(((ContextWrapper) context).getBaseContext());
        }
      }
    
      return getApplicationManager(context);
    }
    
    

    这里做了很多Context类型的区分,只要就是得到不同的生命周期类型:

    • 在主线程并且不是Application,判断下是FragmentActivity还是Activity,都不是获取BaseContext重新进来判断一遍;
    • 其余都作为Application来绑定生命周期。

    我们选择FragmentActivity分支来继续往下追:

    @NonNull
    public RequestManager get(@NonNull FragmentActivity activity) {
      if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
      } else {
        assertNotDestroyed(activity);
        frameWaiter.registerSelf(activity);
        FragmentManager fm = activity.getSupportFragmentManager(); ①
        return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
      }
    }
    
      @NonNull
    private RequestManager supportFragmentGet(
        @NonNull Context context,
        @NonNull FragmentManager fm,
        @Nullable Fragment parentHint,
        boolean isParentVisible) {
      SupportRequestManagerFragment current = 
        getSupportRequestManagerFragment(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); ④
        if (isParentVisible) {
          requestManager.onStart();
        }
        current.setRequestManager(requestManager); ⑤
      }
      return requestManager;
    }
    
    
    • 第一步获取Activity对应的FragmentManager
    • 第二步根据FragmentManager获取对应Fragment,如果没有创建一个新的SupportRequestManagerFragment对象,并且放入到Map中;如果已经存在,直接从Map中获取;
    • 第三步,从Fragment中获取RequestManager对象;
    • 第四步,如果没有获取到,就重新创建一个新的对象,第五步就是将新的RequestManagerFragment绑定。

    这里的SupportRequestManagerFragment其实就是一个空布局的Fragment,主要作用是感知Activity的生命周期。

    RequestManager.load(url)

    com.bumptech.glide.RequestManager#load(java.lang.String)
    
    public RequestBuilder<Drawable> load(@Nullable String string) {
      return asDrawable().load(string);
    }
    
    public RequestBuilder<Drawable> asDrawable() {
      return as(Drawable.class);
    }
      
    public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
      return new RequestBuilder<>(glide, this, resourceClass, context);
    }
        
    public RequestBuilder<TranscodeType> load(@Nullable String string) {
      return loadGeneric(string);
    }
          
    private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
      if (isAutoCloneEnabled()) {
        return clone().loadGeneric(model);
      }
      this.model = model;
      isModelSet = true;
      return selfOrThrowIfLocked();
    }
    
    

    这个流程逻辑相对比较少的,主要就是创建了一个RequestBuilder对象,并且它的泛型参数是Drawable类型,因为我们分析的是加载Url到指定的ImageView

    RequestBuilder.into(iv)

    com.bumptech.glide.RequestBuilder#into(ImageView)
    
    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
      Util.assertMainThread();
      Preconditions.checkNotNull(view);
      BaseRequestOptions<?> requestOptions = this;
      if (!requestOptions.isTransformationSet()
          && requestOptions.isTransformationAllowed()
          && view.getScaleType() != null) {
        switch (view.getScaleType()) { ①
          case CENTER_CROP:
            requestOptions = requestOptions.clone().optionalCenterCrop();
            break;
            ..... 省略其它缩放类型
        }
      }
    
      return into(
          glideContext.buildImageViewTarget(view, transcodeClass),
          /*targetListener=*/ null,
          requestOptions,
          Executors.mainThreadExecutor()); ②
    }
    
    
    • 第一处查看ImageView是否设置了缩放类型,如果有添加类型至RequestOptions中;

    • 进入into()方法中具体执行,这里传了四个参数:

      • 第一个ImageView目标,包含了资源类型就是Drawable.class
      • 第二个是请求监听RequestListener,包括了加载失败和资源准备完成两个回调,这里传的是空值;
      • 第三个是请求的选项RequestOptions
      • 第四个是回调的线程池,这边最终回调到主线程。

    into(target,reqeuestListener,options,callbackExecutor)

    com.bumptech.glide.RequestBuilder#into
    
    private <Y extends Target<TranscodeType>> Y into(
        @NonNull Y target,
        @Nullable RequestListener<TranscodeType> targetListener,
        BaseRequestOptions<?> options,
        Executor callbackExecutor) {
      Preconditions.checkNotNull(target);
      if (!isModelSet) {
        throw new IllegalArgumentException("You must call #load() before calling #into()");
      }
    
      Request request = buildRequest(target, targetListener, options, callbackExecutor); ①
    
      Request previous = target.getRequest(); ②
      if (request.isEquivalentTo(previous)
          && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { ③
        if (!Preconditions.checkNotNull(previous).isRunning()) {
          previous.begin();
        }
        return target;
      }
    
      requestManager.clear(target);
      target.setRequest(request);
      requestManager.track(target, request); ④
    
      return target;
    }
    
    
    • 第一步,构建一个Request对象,这个下面着重介绍下;

    • 第二步从Target对象里面获取已存在的请求;

    • 第三步判断是否可以复用已存在的请求:

      • 第一个条件是requestprevious是否参数一致,请求类型一致;
      • 是否设置了跳过缓存并且previous已经完成。
    • 第四步如果不能复用,那么就使用构建的Request对象,最后调用RequestManager.track(target,request)方法。

    接着我们先暂停主流程,进入构建Request对象的逻辑里面。

    buildRequest(target,targetListener,opstions,callbackExecutor)

    com.bumptech.glide.RequestBuilder#buildRequest  
    
    private Request buildRequest(
        Target<TranscodeType> target,
        @Nullable RequestListener<TranscodeType> targetListener,
        BaseRequestOptions<?> requestOptions,
        Executor callbackExecutor) {
      return buildRequestRecursive(
          /*requestLock=*/ new Object(),
          target,
          targetListener,
          /*parentCoordinator=*/ null,
          transitionOptions,
          requestOptions.getPriority(),
          requestOptions.getOverrideWidth(),
          requestOptions.getOverrideHeight(),
          requestOptions,
          callbackExecutor);
    }
    

    这里直接调用buildRequestRecursive()方法。

    com.bumptech.glide.RequestBuilder#buildRequestRecursive
    
    private Request buildRequestRecursive(
        Object requestLock,
        Target<TranscodeType> target,
        @Nullable RequestListener<TranscodeType> targetListener,
        @Nullable RequestCoordinator parentCoordinator,
        TransitionOptions<?, ? super TranscodeType> transitionOptions,
        Priority priority,
        int overrideWidth,
        int overrideHeight,
        BaseRequestOptions<?> requestOptions,
        Executor callbackExecutor) {
        
        // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
        ErrorRequestCoordinator errorRequestCoordinator = null; 
        if (errorBuilder != null) { ①
            errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
            parentCoordinator = errorRequestCoordinator;
        }
        
        Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor); ②
        
        if (errorRequestCoordinator == null) { ③
            return mainRequest;
        }
        
        int errorOverrideWidth = errorBuilder.getOverrideWidth();
        int errorOverrideHeight = errorBuilder.getOverrideHeight();
        if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
            errorOverrideWidth = requestOptions.getOverrideWidth();
            errorOverrideHeight = requestOptions.getOverrideHeight();
        }
        
        Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
        errorRequestCoordinator.setRequests(mainRequest, errorRequest); ④
        return errorRequestCoordinator;
    }
    
    • 第一步,判断errorBuilder是否为空,这个errorBuilder是我们通过RequestBuilder.error()设置的,如果不为空,将会生成一个协调器ErrorRequestCoordinator用于协调下面mainRequesterrorRequest,现在我们默认未设置,只看主流程;
    • 第二步通过buildThumbnailRequestRecursive()生成mainRequest
    • 第三步如果errorRequestCoordinator为空直接返回mainRequest
    • 第四步如果errorRequestCoordinator不为空还将生成一个errorRequest

    接着主流程我们看看mainRequest是怎么生成的。

    buildThumbnailRequestRecursive()

    com.bumptech.glide.RequestBuilder#buildThumbnailRequestRecursive
    
    private Request buildThumbnailRequestRecursive(
          Object requestLock,
          Target<TranscodeType> target,
          RequestListener<TranscodeType> targetListener,
          @Nullable RequestCoordinator parentCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight,
          BaseRequestOptions<?> requestOptions,
          Executor callbackExecutor) {
        if (thumbnailBuilder != null) {
          // Recursive case: contains a potentially recursive thumbnail request builder.
          if (isThumbnailBuilt) {
            throw new IllegalStateException(
                "You cannot use a request as both the main request and a "
                    + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
          }
    
          TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
              thumbnailBuilder.transitionOptions;
    
          // Apply our transition by default to thumbnail requests but avoid overriding custom options
          // that may have been applied on the thumbnail request explicitly.
          if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
            thumbTransitionOptions = transitionOptions;
          }
    
          Priority thumbPriority =
              thumbnailBuilder.isPrioritySet()
                  ? thumbnailBuilder.getPriority()
                  : getThumbnailPriority(priority);
    
          int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
          int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
          if (Util.isValidDimensions(overrideWidth, overrideHeight)
              && !thumbnailBuilder.isValidOverride()) {
            thumbOverrideWidth = requestOptions.getOverrideWidth();
            thumbOverrideHeight = requestOptions.getOverrideHeight();
          }
    
          ThumbnailRequestCoordinator coordinator =
              new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
          Request fullRequest =
              obtainRequest(
                  requestLock,
                  target,
                  targetListener,
                  requestOptions,
                  coordinator,
                  transitionOptions,
                  priority,
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
          isThumbnailBuilt = true;
          // Recursively generate thumbnail requests.
          Request thumbRequest =
              thumbnailBuilder.buildRequestRecursive(
                  requestLock,
                  target,
                  targetListener,
                  coordinator,
                  thumbTransitionOptions,
                  thumbPriority,
                  thumbOverrideWidth,
                  thumbOverrideHeight,
                  thumbnailBuilder,
                  callbackExecutor);
          isThumbnailBuilt = false;
          coordinator.setRequests(fullRequest, thumbRequest);
          return coordinator;
        } else if (thumbSizeMultiplier != null) {
          // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
          ThumbnailRequestCoordinator coordinator =
              new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
          Request fullRequest =
              obtainRequest(
                  requestLock,
                  target,
                  targetListener,
                  requestOptions,
                  coordinator,
                  transitionOptions,
                  priority,
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
          BaseRequestOptions<?> thumbnailOptions =
              requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
    
          Request thumbnailRequest =
              obtainRequest(
                  requestLock,
                  target,
                  targetListener,
                  thumbnailOptions,
                  coordinator,
                  transitionOptions,
                  getThumbnailPriority(priority),
                  overrideWidth,
                  overrideHeight,
                  callbackExecutor);
    
          coordinator.setRequests(fullRequest, thumbnailRequest);
          return coordinator;
        } else {
          // Base case: no thumbnail.
          return obtainRequest(
              requestLock,
              target,
              targetListener,
              requestOptions,
              parentCoordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
        }
      }
    

    这边我们先忽略缩略图的设置,直接看最后else分支中,直接返回的是obtainRequest()方法的返回值。

    com.bumptech.glide.RequestBuilder#obtainRequest
    
    private Request obtainRequest(
        Object requestLock,
        Target<TranscodeType> target,
        RequestListener<TranscodeType> targetListener,
        BaseRequestOptions<?> requestOptions,
        RequestCoordinator requestCoordinator,
        TransitionOptions<?, ? super TranscodeType> transitionOptions,
        Priority priority,
        int overrideWidth,
        int overrideHeight,
        Executor callbackExecutor) {
      return SingleRequest.obtain(
          context,
          glideContext,
          requestLock,
          model,
          transcodeClass,
          requestOptions,
          overrideWidth,
          overrideHeight,
          priority,
          target,
          targetListener,
          requestListeners,
          requestCoordinator,
          glideContext.getEngine(),
          transitionOptions.getTransitionFactory(),
          callbackExecutor);
    }
    

    到这里停止,我们最终可以看到其实经过很多层最后得到的是SingleRequest对象。接着我们需要跳回到into()方法中的最后一行代码RequestManager.track(target,request),这里面的request就是我们刚刚看到的SingleRequest对象。

    RequestManager.track(target,request)

    com.bumptech.glide.RequestManager#track
    
    synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
      targetTracker.track(target); ①
      requestTracker.runRequest(request); ②
    }
    
    com.bumptech.glide.manager.TargetTracker#track
    private final Set<Target<?>> targets =
        Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());
    
    public void track(@NonNull Target<?> target) {
      targets.add(target);
    }
    
    com.bumptech.glide.manager.RequestTracker#runRequest
    private final Set<Request> requests =
        Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
    private final Set<Request> pendingRequests = new HashSet<>();
    
    public void runRequest(@NonNull Request request) {
      requests.add(request);
      if (!isPaused) {
        request.begin();
      } else {
        request.clear();
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          Log.v(TAG, "Paused, delaying request");
        }
        pendingRequests.add(request);
      }
    }
    

    这个方法是加了synchronized为了线程安全,一共作了两个操作:

    • 第一步将target添加到TargetTracker.targets集合中;
    • 第二步运行SingleRequest,首先将SingleRequest添加到RequestTracker.requests集合中,如果当前不是暂停状态,直接调用SingleRequest.begin()方法,如果当前是暂停状态,那么就将SingleRequest添加到待定的集合中pendingRequests

    我们继续往下看,进入SingleRequest.begin()方法。

    SingleRequest.begin()

    com.bumptech.glide.request.SingleRequest#begin
    
    public void begin() {
      synchronized (requestLock) {
        assertNotCallingCallbacks();
        stateVerifier.throwIfRecycled();
        startTime = LogTime.getLogTime();
        if (model == null) { ①
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            width = overrideWidth;
            height = overrideHeight;
          }
          int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
          onLoadFailed(new GlideException("Received null model"), logLevel);
          return;
        }
    
        if (status == Status.RUNNING) { ②
          throw new IllegalArgumentException("Cannot restart a running request");
        }
        if (status == Status.COMPLETE) { ③
          onResourceReady(
              resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
          return;
        }
        experimentalNotifyRequestStarted(model);
    
        cookie = GlideTrace.beginSectionAsync(TAG);
        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) { ④
          onSizeReady(overrideWidth, overrideHeight);
        } else {
          target.getSize(this);
        }
    
        if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
            && canNotifyStatusChanged()) { ⑤
          target.onLoadStarted(getPlaceholderDrawable());
        }
        if (IS_VERBOSE_LOGGABLE) {
          logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
      }
    }
    

    整个begin()方法中,我么分为了5步来梳理:

    • 第一步model也就是url如果为空,直接返回,回调onLoadFailed()
    • 第二步判断当前状态如果是RUNNING状态,直接抛异常,一个Request只能同时执行一次;
    • 第三步判断当前状态如果是COMMPLETE状态,那么可以直接返回resourceonResourceReady()后续会将获取到的Drawable显示到指定的ImageView中,这个后面会有解析;
    • 第四步判断宽高是否有效,如果有效直接进入onSizeReady()方法,开启加载模式,此时状态会进入RUNNING状态
    • 第五步如果当前状态为RUNNING或者WAITING_FOR_SIZE状态,显示占位图。

    SingleRequest.onSizeReady(width,height)

    com.bumptech.glide.request.SingleRequest#onSizeReady  
    
    public void onSizeReady(int width, int height) {
      stateVerifier.throwIfRecycled();
      synchronized (requestLock) {
        if (status != Status.WAITING_FOR_SIZE) {
          return;
        }
        status = Status.RUNNING; ①
    
        float sizeMultiplier = requestOptions.getSizeMultiplier();
        this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
        this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
        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,
                callbackExecutor); ②
      }
    }
    
    • 第一步先将状态设置为RUNNING
    • 启动Engine引擎去加载图片。

    Engine.load()

    com.bumptech.glide.load.engine.Engine#load
    
    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,
          boolean isScaleOnlyOrNoTransform,
          Options options,
          boolean isMemoryCacheable,
          boolean useUnlimitedSourceExecutorPool,
          boolean useAnimationPool,
          boolean onlyRetrieveFromCache,
          ResourceCallback cb,
          Executor callbackExecutor) {
        long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
    
        EngineKey key =
            keyFactory.buildKey(
                model,
                signature,
                width,
                height,
                transformations,
                resourceClass,
                transcodeClass,
                options); ①
    
        EngineResource<?> memoryResource;
        synchronized (this) {
          memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); ②
    
          if (memoryResource == null) {
            return waitForExistingOrStartNewJob(
                glideContext,
                model,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                options,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache,
                cb,
                callbackExecutor,
                key,
                startTime); ③
          }
        }
    
        // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
        // deadlock.
        cb.onResourceReady(
            memoryResource, DataSource.MEMORY_CACHE, false); ④
        return null;
      }
    
    • 第一步生成EngineKey,用作后续写缓存或者读缓存使用;
    • 第二步去缓存中寻找,先从活动缓存ActivityResource,再去内存缓存中MemoryCache中;
    • 第三步如果内存缓存中没有命中,那么开始新的任务

    Engine.waitForExistingOrStartNewJob()

    com.bumptech.glide.load.engine.Engine#waitForExistingOrStartNewJob
    
    private <R> LoadStatus waitForExistingOrStartNewJob(...) {
        // 从Jobs map中查找,已经存在就直接返回
        EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); ①
        if (current != null) {
          current.addCallback(cb, callbackExecutor);
          if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Added to existing load", startTime, key);
          }
          return new LoadStatus(cb, current);
        }
        // 创建EngineJob
        EngineJob<R> engineJob =
            engineJobFactory.build(
                key,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache); ②
        // 创建解码器DecodeJob,
        // 注意最后一次参数,传的是EngineJob,因为EngineJob实现了DecodeJob.Callback
        DecodeJob<R> decodeJob =
            decodeJobFactory.build(
                glideContext,
                model,
                key,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                onlyRetrieveFromCache,
                options,
                engineJob); ③
        // 存到Jobs map中
        jobs.put(key, engineJob);
        // 将EngineJob和callback,callbackExecutor绑定
        // cb是回调资源是否加载完成,callbackExecutor是回调到主线程
        engineJob.addCallback(cb, callbackExecutor);
        // 调用EngineJob.start()其实就是调用线程池执行Runnable,而decodeJob就是实现了Runnable
        engineJob.start(decodeJob); ④
    
        if (VERBOSE_IS_LOGGABLE) {
          logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
      }
    
    • 第一步查找是否已经存在此Job,若已存在直接返回;
    • 第二步创建EngineJob对象,用于开启任务,回调资源加载成功和失败;
    • 第三步创建DecodeJob对象,用于加载资源,操作缓存等,并且此时DecodeJob已经和EngineJobCallback形式绑定在一起;
    • 第四步开始执行DecodeJobrun()方法,EngineJob.start()内部就是调用线程池的excute()方法,传入的正是DecodeJob,所以我们进入DecodeJob.run()方法继续分析。

    DecodeJob.run()

    com.bumptech.glide.load.engine.DecodeJob#run 
    
    public void run() {
      // This should be much more fine grained, but since Java's thread pool implementation silently
      // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
      // that something is failing.
      GlideTrace.beginSectionFormat("DecodeJob#run(reason=%s, model=%s)", runReason, model);
      // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
      // ensure that the fetcher is cleaned up either way.
      DataFetcher<?> localFetcher = currentFetcher;
      try {
        // 如果被取消了,直接回调失败
        if (isCancelled) {
          notifyFailed();
          return;
        }
        // 下一步逻辑
        runWrapped(); ①
      } catch (CallbackException e) {
        throw e;
      } finally {
        if (localFetcher != null) {
          // 回收资源,Http Stream、File Stream等
          localFetcher.cleanup();
        }
        GlideTrace.endSection();
      }
    }
    

    run()方法内部直接进入runWrapped()方法。

    DecodeJob#runWrapped

    com.bumptech.glide.load.engine.DecodeJob#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);
      }
    }
    
    private Stage getNextStage(Stage current) {
      switch (current) {
        case INITIALIZE:
          return diskCacheStrategy.decodeCachedResource()
              ? Stage.RESOURCE_CACHE
              : getNextStage(Stage.RESOURCE_CACHE);
        case RESOURCE_CACHE:
          return diskCacheStrategy.decodeCachedData()
              ? Stage.DATA_CACHE
              : getNextStage(Stage.DATA_CACHE);
        case DATA_CACHE:
          // Skip loading from source if the user opted to only retrieve the resource from cache.
          return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
        case SOURCE:
        case FINISHED:
          return Stage.FINISHED;
        default:
          throw new IllegalArgumentException("Unrecognized stage: " + current);
      }
    }
    
    private DataFetcherGenerator getNextGenerator() {
      switch (stage) {
        case RESOURCE_CACHE:
          return new ResourceCacheGenerator(decodeHelper, this);
        case DATA_CACHE:
          return new DataCacheGenerator(decodeHelper, this);
        case SOURCE:
          return new SourceGenerator(decodeHelper, this);
        case FINISHED:
          return null;
        default:
          throw new IllegalStateException("Unrecognized stage: " + stage);
      }
    }
    
    private enum RunReason {
      /** 首次提交任务 */
      INITIALIZE,
      /** 尝试从磁盘缓存切到内存缓存 */
      SWITCH_TO_SOURCE_SERVICE,
      /**
       * 解码原数据,也就是去加载资源
       */
      DECODE_DATA,
    }
    

    先看下RunReason这个枚举类,一共有三个状态:

    • INITIALIZE:代表首次提交任务;
    • SWITCH_TO_SOURCE_SERVICE:磁盘缓存中有,切到内存缓存中;
    • DECODE_DATA:直接去加载资源(未命中缓存)。

    然后我们再看runWrapped()方法,runReason变量在init()方法中赋值为INITIALIZE状态。这样我们先从第一个case查看:默认缓存全开

    • 首先通过getNextStage(Stage.INITIALIZE)获取下一个阶段,默认缓存全开,下一状态为Stage.RESOURCE_CACHE
    • 然后通过getNextGenerator()获取到下一个DataFetcherGenerator,由于上面StageRESOURCE_CACHE,所以返回的是ResourceCacheGenerator,这个Generator就是从磁盘缓存中获取是否有经过编解码、转码之后的缓存;
    • 最后调用runGenerators()

    DecodeJob#runGenerators

    com.bumptech.glide.load.engine.DecodeJob#runGenerators
    
    private void runGenerators() {
      currentThread = Thread.currentThread();
      startFetchTime = LogTime.getLogTime();
      boolean isStarted = false;
      // while循环,知道stage==SOURCE,才结束
      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();
      }
    }
    

    这里我们可以看到,进入while循环,其中currentGenerator.startNext()是获取ResourceCacheGenerator是否已存在缓存,如果存在那么就直接返回了,不存在继续往下走,直到stage=Stage.Source,然后调用reschedule()方法。

    DecodeJob#reschedule

    com.bumptech.glide.load.engine.DecodeJob#reschedule
    
    public void reschedule() {
      // 首先将runReason置为SWITCH_TO_SOURCE_SERVICE
      runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
      // 然后调用callback.reschedule(this)
      callback.reschedule(this);
    }
    
    • 第一步改变runReason值,置为SWITCH_TO_SOURCE_SERVICE
    • 第二步调用callback.reschedule()方法,前面创建DecodeJob对象的时候提过,这里的callback就是EngineJob对象,所以我们又得回到EngineJob.reschedule()方法。

    EngineJob#reschedule

    com.bumptech.glide.load.engine.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);
    }
    

    这里拿到sourceExecutor的线程池,再去执行DecodeJob.run()方法...有点头晕

    但是几个状态我们需要知道,对于DecodeJob,它的runReason已经是SWITCH_TO_SOURCE_SERVICE并且stageSOURCE了。

    到这之后又会回到DecodeJob.run()方法,然后去DataSourceGenerator去查找是否有源文件缓存,如果有直接返回,没有就去SourceGenerator去加载资源。

    总结加载流程:

    • 先从ResourceCacheGenerator中去寻找是否有经过转换、解码之后的磁盘文件缓存,这个缓存要比源文件缓存小;
    • 再从DataSourceGenerator中寻找源文件磁盘缓存,这个是加载的源文件直接写入缓存;
    • 如果都没命中,那么就去Http请求资源,资源请求回来之后先写入磁盘缓存,再返回到Target

    最后我们看下资源拿到之后是如何回调到Target,当资源得到之后,会调用onResourceReady()回调方法,此方法的回调链为:SingleRequest#onResourceReady->ImageViewTarget#onResourceReady->mageViewTarget#setResourceInternal->DrawableImageViewTarget#setResource

    com.bumptech.glide.request.target.DrawableImageViewTarget#setResource
    
    protected void setResource(@Nullable Drawable resource) {
      view.setImageDrawable(resource);
    }
    
    

    最终在DrawableImageViewTarget中降Resource设置给ImageView

    为了大家更便捷的对这源码分析,我将方法引用都放在代码块的最上方,大家可以参考。

    Glide源码很多不容易一时间啃完,大家可以多读读多看看,了解下每个对象的工作内容,然后再去反复理解,加载逻辑中涉及到缓存的查找已经资源的加载,理清楚之后就会觉得豁然开朗,加油~

    相关文章

      网友评论

        本文标题:Android 高频面试题解析:Glide流程解析

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