美文网首页
Glide源码分析

Glide源码分析

作者: 西瓜家族 | 来源:发表于2020-02-09 00:13 被阅读0次

    它支持拉取、解码、展示,视频快照、图片和GIF动画。提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 使用简明的流式(链式)语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求,因此搞懂这条链式调用的代码都做了什么准备工作,Glide图片加载的大概框架也就明白了许多。

     Glide.with(context)
            .load("")
            .into(imageView);
    

    一、with()方法

    概述:with()通过RequestManagerRetriever的单例,静态get方法拿到其对象实例,然后通过成员函数get方法,通过getApplicationManager(Context)方法最终拿到了RequestManager对象实例

    public static RequestManager with(@NonNull FragmentActivity activity) {
        return getRetriever(activity).get(activity);
      }
    

    RequestManagerRetriever.class

    private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        // Context could be null for other reasons (ie the user passes in null), but in practice it will
        // only occur due to errors with the Fragment lifecycle.
        Preconditions.checkNotNull(
            context,
            "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
                + "returns null (which usually occurs when getActivity() is called before the Fragment "
                + "is attached or after the Fragment is destroyed).");
        return Glide.get(context).getRequestManagerRetriever();
    }
    
    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) {
            return get(((ContextWrapper) context).getBaseContext());
          }
        }
    
        return getApplicationManager(context);
      }
    
    public RequestManager get(@NonNull FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm, null /*parentHint*/);
        }
    }
      
     public RequestManager get(@NonNull Activity activity) {
        if (Util.isOnBackgroundThread()) {
          return get(activity.getApplicationContext());
        } else {
          assertNotDestroyed(activity);
          android.app.FragmentManager fm = activity.getFragmentManager();
          return fragmentGet(activity, fm, null /*parentHint*/);
        }
      }  
    
     /** 
      * 通过 get((FragmentActivity) context);和get((Activity) context);
      * 真正获取RequestManager在supportFragmentGet(),fragmentGet()两个方法
      * 两个方法功能一致
      */
     private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
          @Nullable Fragment parentHint) {
        // 创建一个隐藏fragment用于管理Glide加载生命周期  
        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 =
              // 创建RequestManager
              factory.build(
                  glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          // 将requestManager保存在创建的fragment中,用于生命周期管理          
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    

    通过上面源码可以发现get方法其实分为两种,即application类型和非application类型的参数。如果是application类型参数,会调用getApplicationManager(Context),最后返回一个RequestManager对象实例;如果是非application类型参数,最后都会向当前的Activity添加一个隐藏的Fragment。

    Glige需要拿到加载的生命周期,当我们在Activity加载一张图片,图片还没有加载,Activity就被销毁了,那图片就不用加载。把Glide放到Fragment中,当Activity销毁,Fragment是可以监听到的,这样就可以实现需求了

    二、load()方法

      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) {
          // 创建一个RequestBuilder实例
        return new RequestBuilder<>(glide, this, resourceClass, context);
      }
    
      public RequestBuilder<TranscodeType> load(@Nullable String string) {
        return loadGeneric(string);
      }
      
      private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        this.model = model;
        isModelSet = true;
        return this;
      }
    

    三、into()方法

    概述:1.初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),2.使用最原始的HTTPConnect网络连接,读取文件流,3.根据文件判断是GIF动图还是Bitmap静态图片,4.通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件

    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        // 主线程
        Util.assertMainThread();
        Preconditions.checkNotNull(view);
    
        RequestOptions requestOptions = this.requestOptions;
        if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
          // Clone in this method so that if we use this RequestBuilder to load into a View and then
          // into a different target, we don't retain the transformation applied based on the previous
          // View's scale type.
          switch (view.getScaleType()) {
            case CENTER_CROP:
              requestOptions = requestOptions.clone().optionalCenterCrop();
              break;
            case CENTER_INSIDE:
              requestOptions = requestOptions.clone().optionalCenterInside();
              break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
              requestOptions = requestOptions.clone().optionalFitCenter();
              break;
            case FIT_XY:
              requestOptions = requestOptions.clone().optionalCenterInside();
              break;
            case CENTER:
            case MATRIX:
            default:
              // Do nothing.
          }
        }
        /**
         * 重点glideContext是在Glide构造方法中创建的,GlideContext类是一个全局的
         * 为所有在Glide中加载任务保存和提供各种registries和classes类
         * 就是一个类似工具类的存在
         * transcodeClass:这里我们传入的是Drawable(在RequestManager中的as()方法传入)
         */
        return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions);
      }
    
    

    跟踪glideContext.buildImageViewTarget()进入ImageViewTargetFactory中
    ImageViewTargetFactory工厂类根据不同clazz参数来构建Target对象,clazz参数有两种情况:
    1、使用Glide加载图片的时候调用了asBitmap()方法,这里就会构建BitmapImageViewTarget对象。
    2、默认都是生成了DrawableImageViewTarget对象。

     public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
          @NonNull Class<Z> clazz) {
        if (Bitmap.class.equals(clazz)) {
          return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
        } else if (Drawable.class.isAssignableFrom(clazz)) {
          return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
        } else {
          throw new IllegalArgumentException(
              "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
        }
      }
    

    ViewTarget创建后我们来进入上面into方法:

    private <Y extends Target<TranscodeType>> Y into(
          @NonNull Y target,
          @Nullable RequestListener<TranscodeType> targetListener,
          @NonNull RequestOptions options) {
        Util.assertMainThread();
        Preconditions.checkNotNull(target);
        if (!isModelSet) {
          throw new IllegalArgumentException("You must call #load() before calling #into()");
        }
    
        options = options.autoClone();
        //***重点,用来发出加载图片请求的,它是Glide中非常关键的一个组件***
        Request request = buildRequest(target, targetListener, options);
    
        Request previous = target.getRequest();
        if (request.isEquivalentTo(previous)
            && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          request.recycle();
          // If the request is completed, beginning again will ensure the result is re-delivered,
          // triggering RequestListeners and Targets. If the request is failed, beginning again will
          // restart the request, giving it another chance to complete. If the request is already
          // running, we can let it continue running without interruption.
          if (!Preconditions.checkNotNull(previous).isRunning()) {
            // Use the previous request rather than the new one to allow for optimizations like skipping
            // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
            // that are done in the individual Request.
            previous.begin();
          }
          return target;
        }
    
        requestManager.clear(target);
        target.setRequest(request);
        requestManager.track(target, request);
    
        return target;
      }
    

    接着跟踪buildRequest(target, targetListener, options)方法进入:

    private Request buildRequestRecursive(
          Target<TranscodeType> target,
          @Nullable RequestListener<TranscodeType> targetListener,
          @Nullable RequestCoordinator parentCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight,
          RequestOptions requestOptions) {
    
        // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
        ErrorRequestCoordinator errorRequestCoordinator = null;
        // 这里如果调用了RequestBuilder error()将会进行错误处理
        if (errorBuilder != null) {
          errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
          parentCoordinator = errorRequestCoordinator;
        }
        
        // 重点
        Request mainRequest =
            buildThumbnailRequestRecursive(
                target,
                targetListener,
                parentCoordinator,
                transitionOptions,
                priority,
                overrideWidth,
                overrideHeight,
                requestOptions);
    
        if (errorRequestCoordinator == null) {
          return mainRequest;
        }
    
        int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
        int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
        if (Util.isValidDimensions(overrideWidth, overrideHeight)
            && !errorBuilder.requestOptions.isValidOverride()) {
          errorOverrideWidth = requestOptions.getOverrideWidth();
          errorOverrideHeight = requestOptions.getOverrideHeight();
        }
    
        Request errorRequest = errorBuilder.buildRequestRecursive(
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.requestOptions.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder.requestOptions);
        errorRequestCoordinator.setRequests(mainRequest, errorRequest);
        return errorRequestCoordinator;
      }
    

    继续跟踪:

    private Request buildThumbnailRequestRecursive(
          Target<TranscodeType> target,
          RequestListener<TranscodeType> targetListener,
          @Nullable RequestCoordinator parentCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight,
          RequestOptions requestOptions) {
            .......
            // 省略缩略图的出来代码
            .......
          // Base case: no thumbnail.
          return obtainRequest(
              target,
              targetListener,
              requestOptions,
              parentCoordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      }
      
      private Request obtainRequest(
          Target<TranscodeType> target,
          RequestListener<TranscodeType> targetListener,
          RequestOptions requestOptions,
          RequestCoordinator requestCoordinator,
          TransitionOptions<?, ? super TranscodeType> transitionOptions,
          Priority priority,
          int overrideWidth,
          int overrideHeight) {
        return SingleRequest.obtain(
            context,
            glideContext,
            model,
            transcodeClass,
            requestOptions,
            overrideWidth,
            overrideHeight,
            priority,
            target,
            targetListener,
            requestListener,
            requestCoordinator,
            glideContext.getEngine(),
            transitionOptions.getTransitionFactory());
      }
    

    随后我们进入SingleRequest.obtain()方法这个方法真正生成一个request:SingleRequest实例
    创建好Request实例,我们回到into()方法中,接着:

    Request request = buildRequest(target, targetListener, options);
    Request previous = target.getRequest();
        if (request.isEquivalentTo(previous)
            && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          request.recycle();
          // If the request is completed, beginning again will ensure the result is re-delivered,
          // triggering RequestListeners and Targets. If the request is failed, beginning again will
          // restart the request, giving it another chance to complete. If the request is already
          // running, we can let it continue running without interruption.
          if (!Preconditions.checkNotNull(previous).isRunning()) {
            // Use the previous request rather than the new one to allow for optimizations like skipping
            // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
            // that are done in the individual Request.
            previous.begin();
          }
          return target;
        }
        
        requestManager.clear(target);
        target.setRequest(request);
        // 最后调用这个方法
        requestManager.track(target, request);
    

    接着跟踪track()方法跟踪到下面方法中:

      public void runRequest(Request request) {
        // 请求添加到集合中统一管理
        requests.add(request);
        // 先判断Glide当前是不是Paused(暂停)状态
        if (!isPaused) {
          // 执行SingleRequest中的begin()方法
          request.begin();
        } else {
          // 将Request对象添加到待执行队列里面,等暂停状态解除后再执行
          pendingRequests.add(request);
        }
      }
    

    SingleRequest.java

    public void begin() {
        assertNotCallingCallbacks();
        stateVerifier.throwIfRecycled();
        startTime = LogTime.getLogTime();
        if (model == null) {
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            width = overrideWidth;
            height = overrideHeight;
          }
          // Only log at more verbose log levels if the user has set a fallback drawable, because
          // fallback Drawables indicate the user expects null models occasionally.
          int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
          // 如果model==null,最终会调用setErrorPlaceholder(),设置错误占位图
          onLoadFailed(new GlideException("Received null model"), logLevel);
          return;
        }
    
        if (status == Status.RUNNING) {
          throw new IllegalArgumentException("Cannot restart a running request");
        }
    
        // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
        // that starts an identical request into the same Target or View), we can simply use the
        // resource and size we retrieved the last time around and skip obtaining a new size, starting a
        // new load etc. This does mean that users who want to restart a load because they expect that
        // the view size has changed will need to explicitly clear the View or Target before starting
        // the new load.
        if (status == Status.COMPLETE) {
          onResourceReady(resource, DataSource.MEMORY_CACHE);
          return;
        }
    
        // Restarts for requests that are neither complete nor running can be treated as new requests
        // and can run again from the beginning.
    
        // 图片的一个状态赋值
        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          // 手动为图片指定了宽高
          onSizeReady(overrideWidth, overrideHeight);
        } else {
          // 没有指定宽高,getSize()方法内部会根据ImageView控件的layout_width和layout_height值做一系列的计算,来算出图片对应的宽高,总之在计算完之后,最终还是会调用onSizeReady()方法
          target.getSize(this);
        }
    
        if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
            && canNotifyStatusChanged()) {
          // 在图片请求开始之前会先加载占位图,这就是Glide的placeholder()和 error()这两个占位图API底层的实现原理。 
          target.onLoadStarted(getPlaceholderDrawable());
        }
        if (IS_VERBOSE_LOGGABLE) {
          logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
      }
    
    public void onSizeReady(int width, int height) {
        stateVerifier.throwIfRecycled();
        if (IS_VERBOSE_LOGGABLE) {
          logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
        if (status != Status.WAITING_FOR_SIZE) {
          return;
        }
        // 给图片赋值一个运行状态
        status = Status.RUNNING;
    
        float sizeMultiplier = requestOptions.getSizeMultiplier();
        this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
        this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
    
        if (IS_VERBOSE_LOGGABLE) {
          logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
        }
        // 真正的去加载图片
        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);
    
        // This is a hack that's only useful for testing right now where loads complete synchronously
        // even though under any executor running on any thread but the main thread, the load would
        // have completed asynchronously.
        if (status != Status.RUNNING) {
          loadStatus = null;
        }
        if (IS_VERBOSE_LOGGABLE) {
          logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
      }
    
    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) {
        Util.assertMainThread();
        long startTime = LogTime.getLogTime();
    
        // key是用来标记每个请求
        EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
            resourceClass, transcodeClass, options);
    
        // 第一步  从active Resources中获取
        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;
        }
    
        // 第二布  从缓存中获取
        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;
        }
        // active Resources和缓存中都没有请求的资源,创建一个EngineJob
        EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
        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,
                useAnimationPool,
                onlyRetrieveFromCache);
    
        DecodeJob<R> decodeJob =
            decodeJobFactory.build(
                glideContext,
                model,
                key,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                onlyRetrieveFromCache,
                options,
                engineJob);
    
        jobs.put(key, engineJob);
    
        // 添加图片资源下载完成后的回调
        engineJob.addCallback(cb);
        // 开始下载任务
        engineJob.start(decodeJob);
    
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
      }
    

    继续进入engineJob.start()方法:

     public void start(DecodeJob<R> decodeJob) {
        this.decodeJob = decodeJob;
        // 这里决定用什么线程池来执行,这里我们拿到的是磁盘缓存中diskCacheExecutor
        GlideExecutor executor = decodeJob.willDecodeFromCache()
            ? diskCacheExecutor
            : getActiveSourceExecutor(); 
        executor.execute(decodeJob);
      }
      
      boolean willDecodeFromCache() {
        Stage firstStage = getNextStage(Stage.INITIALIZE);
        return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
      }
    

    DecodeJob是一个Runnable,接下来看他的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.
        TraceCompat.beginSection("DecodeJob#run");
        // 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 (Throwable t) {
          ......
        } finally {
          // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
          // close in all cases anyway.
          if (localFetcher != null) {
            localFetcher.cleanup();
          }
          TraceCompat.endSection();
        }
      }
    
      private void runWrapped() {
         switch (runReason) {
          case INITIALIZE:
            // stage 是一个状态标记,标记从哪里decode数据
            // 请求开始是这个状态,所以第一次从这里开始
            stage = getNextStage(Stage.INITIALIZE);
            // 第一次拿到的是ResourceCacheGenerator
            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:
            // 第一次执行这里,默认的disk缓存策略是AUTOMATIC,所以状态切换成RESOURCE_CACHE
            return diskCacheStrategy.decodeCachedResource()
                ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
          case RESOURCE_CACHE:
            // 第二次执行到这里,默认AUTOMATIC策略decodeCachedData()返回true
            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:
            // ResourceCache,加载本地Uri资源图片后的缓存
            return new ResourceCacheGenerator(decodeHelper, this);
          case DATA_CACHE:
            // DataCache 图片disk缓存
            return new DataCacheGenerator(decodeHelper, this);
          case SOURCE:
            // 网络加载器
            return new SourceGenerator(decodeHelper, this);
          case FINISHED:
            return null;
          default:
            throw new IllegalStateException("Unrecognized stage: " + stage);
        }
      }
      
       private void runGenerators() {
        currentThread = Thread.currentThread();
        startFetchTime = LogTime.getLogTime();
        boolean isStarted = false;
        while (!isCancelled && currentGenerator != null
            && !(isStarted = currentGenerator.startNext())) {
          // 关注点1,startNext方法
          stage = getNextStage(stage);
          currentGenerator = getNextGenerator();
    
          if (stage == Stage.SOURCE) {
            // 关注点2
            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.
      }
    

    currentGenerator有三个实现类,分别是ResourceCacheGenerator,DataCacheGenerator,SourceGenerator
    图片在进入disk缓存获取的步骤,也就是DecodeJob中run()方法执行的工作:

    1. runWrapped()方法中,获取到的stage是Stage.RESOURCE_CACHE,currentGenerator是ResourceCacheGenerator
    2. 然后执行runGenerators()方法中的currentGenerator.startNext()方法,这个方法是真正加载的图片地方,如果在ResourceCacheGenerator中没有数据进入while中执行
    3. stage变成Stage.DATA_CACHE,currentGenerator是DataCacheGenerator,再次执行循环
    4. 执行DataCacheGenerator的startNext()方法,如果还是没有数据,再次进去while中执行
    5. 如果用户选择仅从缓存检索资源,则跳过从源加载(getNextStage()方法中注释Skip loading from source if the user opted to only retrieve the resource from cache.)
    6. 此时stage是Stage.SOURCE,currentGenerator是SourceGenerator,进入SourceGenerator的startNext()方法.开始网络加载
    

    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 = helper.getLoadData().get(loadDataListIndex++);
          if (loadData != null
              && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
            started = true;
            // //重点开始加载,并且传入回调this
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    请求成功后回调onDataReady()方法

     public void onDataReady(Object data) {
        DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
        if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
          dataToCache = data;
          // We might be being called back on someone else's thread. Before doing anything, we should
          // reschedule to get back onto Glide's thread.
          //重点这个cb callback是DecodeJob
          cb.reschedule();
        } else {
          cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
              loadData.fetcher.getDataSource(), originalKey);
        }
      }
    

    DecodeJob的reschedule():

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

    DecodeJob的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);
      }
    
    public boolean startNext() {
        if (dataToCache != null) {
          Object data = dataToCache;
          dataToCache = null;
          // 重点,前面已经获取到数据dataToCache不再为null
          cacheData(data);
        }
    
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          return true;
        }
        sourceCacheGenerator = null;
    
        loadData = null;
        boolean started = false;
        while (!started && hasNextModelLoader()) {
          loadData = helper.getLoadData().get(loadDataListIndex++);
          if (loadData != null
              && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
            started = true;
            // //重点开始加载,并且传入回调this
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    缓存数据

    private void cacheData(Object dataToCache) {
        long startTime = LogTime.getLogTime();
        try {
          Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
          DataCacheWriter<Object> writer =
              new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
          originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
          helper.getDiskCache().put(originalKey, writer);
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Finished encoding source to cache"
                + ", key: " + originalKey
                + ", data: " + dataToCache
                + ", encoder: " + encoder
                + ", duration: " + LogTime.getElapsedMillis(startTime));
          }
        } finally {
          loadData.fetcher.cleanup();
        }
    
        sourceCacheGenerator =
            new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
      }
    

    所以在上面的方法中会去执行DataCacheGenerator的startNex()方法,和SourceGenerator类似,随后执行DataCacheGenerator的对应回调方法:

    public void onDataReady(Object data) {
        // cb是SourceGenerator
        cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
      }
    

    SourceGenerator

    public void onDataReady(Object data) {
        // cb 是DecodeJob
        cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.RESOURCE_DISK_CACHE,
            currentKey);
      }
    

    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 {
          TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            // decode我们需要的数据
            decodeFromRetrievedData();
          } finally {
            TraceCompat.endSection();
          }
        }
      }
      
      
      private void decodeFromRetrievedData() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey("Retrieved data", startFetchTime,
              "data: " + currentData
              + ", cache key: " + currentSourceKey
              + ", fetcher: " + currentFetcher);
        }
        Resource<R> resource = null;
        try {
          // 解析到资源
          resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
          e.setLoggingDetails(currentAttemptingKey, currentDataSource);
          throwables.add(e);
        }
        if (resource != null) {
          notifyEncodeAndRelease(resource, currentDataSource);
        } else {
          runGenerators();
        }
      }
      
      
      private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
        if (resource instanceof Initializable) {
          ((Initializable) resource).initialize();
        }
    
        Resource<R> result = resource;
        LockedResource<R> lockedResource = null;
        if (deferredEncodeManager.hasResourceToEncode()) {
          lockedResource = LockedResource.obtain(resource);
          result = lockedResource;
        }
    
        // 这里数据已经加载出来
        notifyComplete(result, dataSource);
    
        stage = Stage.ENCODE;
        try {
          if (deferredEncodeManager.hasResourceToEncode()) {
            deferredEncodeManager.encode(diskCacheProvider, options);
          }
        } finally {
          if (lockedResource != null) {
            lockedResource.unlock();
          }
        }
        // Call onEncodeComplete outside the finally block so that it's not called if the encode process
        // throws.
        onEncodeComplete();
      }
      
      
      private void notifyComplete(Resource<R> resource, DataSource dataSource) {
        setNotifiedOrThrow();
        
        // callback 是EngineJob
        callback.onResourceReady(resource, dataSource);
      }
      
      
      public void onResourceReady(Resource<R> resource, DataSource dataSource) {
        this.resource = resource;
        this.dataSource = dataSource;
        // 这里通过主线程handler将当前EngineJob发送到主线程消息队列中
        MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
      }
    

    主线程handler处理消息,最后执行到handleResultOnMainThread()方法中cb.onResourceReady(engineResource, dataSource);cb的实现是最初的SingleRequest,执行SingleRequest的onResourceReady()方法中的target.onResourceReady(result, animation);这里的target的实现是ImageViewTarget,ImageViewTarget也是一个抽象类

    总结

    1. Glide.with(Context)获取一个RequestManager对象,这期间,如果Glide实例没有,会创建一个全局的单实例。在创建RequestManager时,会去将RequestManager绑定到一个隐藏的RequestManagerFragment中进行生命周期管理
    2. load()方法将确定具体的加载类型保存到一个RequestBuilder中,它也保存着其他RequestOptions
    3. into()方法将在RequestBuilder中创建一个SingleRequest实例,随后onSizeReady()方法被调用,engine开始发起请求加载图片
    4. Engine图片加载分为三步,第一步先从active Resources中取,active Resources 是那些至少已经被提供给一个request的并且还没有被释放的,第二步从MemoryCache中获取,如果还是没有,第三步将会创建一个新的请求
    5. 在Engine的load()中创建一个DecodeJob,Engine将它放入线程池中执行,decodeJob先从ResourceCache中获取,再从DataCache中,最后SourceGenerator的startNext()方法中发起网络请求.网络加载完成后先缓存下来,DecodeJob再次运行,在DataCacheGenerator的startNext()中获取到数据,经过层层回调在DecodeJob的decodeFromRetrievedData()方法中将resource解析出来,最后回调到EngineJob的onResourceReady()方法,通过主线程Handler完成线程切换并将当前EngineJob通过Message发送到主线程的消息队列,随后处理,接着回调到SingRequest的onResourceReady()方法,随后回调target的onResourceReady()方法,到这里图片加载到对应的target,完成.
    

    补充:Glide缓存机制

    Glide的缓存分为两种,Resource缓存、Bitmap缓存。

    一、Resource缓存:

    首先Resource缓存就是缓存整体的图片资源文件,缓存它是为了当首次从服务器端下载下来之后,缓存到本地,如果再次使用这个图片,不用去跑网络请求,直接从本地读取,节省流量也提高访问速度。它使用的是三级缓存原理:

    一级缓存:内存缓存,缓存被回收的资源,使用LRU算法(Least Frequently Used,最近最少使用算法),当需要再次使用到被回收的资源时,直接从内存中读取;
    二级缓存:使用弱引用缓存正在使用的资源,当系统执行GC操作时,会回收没有强引用的资源。使用弱引用缓存,既可以缓存当前正在强引用使用的资源,又不阻碍系统回收无引用的资源
    三级缓存:磁盘缓存,网络图片下载成功后,以文件的形式缓存到磁盘中
    1和2都是内存缓存,只不过功能不一样,1是使用LRU算法缓存被GC回收的资源,2是用弱引用缓存正在使用的资源。在复用图片资源的时候首先从回收的内存缓存集合中查找,内存缓存的集合中没有的时候,去弱引用集合查找是否是当前正在使用,没有的话,去磁盘中查找,再没有的时候去网络中查找。

    二、Bitmap缓存:

    Bitmap所占的内存大小由其三部分组成:图片宽,高和Bitmap质量参数

    bitmap内存大小 = 宽*高*质量参数所占的位数,单位是字节b
    
    ALPHA—8就是Alpha是由8位组成的(1B)
    ARGB_4444,4个4位组成16位(2B)
    ARGB_8888,4个8位组成32位(4B)
    RGB_565,R是5位,G是6位,B是5位组成16位(2B),Glide默认bitmap压缩参数就是这个RGB_565,但是它不能显示透明度
    先说一下为什么要进行bitmap压缩,比如在recycleView中加载大量的图片,频繁的创建和回收Bitmap会导致内存波动影响性能,既然这样,我们能不能缓存Bitmap,不要让它老是new和销毁,这应该是Glide去做Bitmap缓存的原因,
    
    Bitmap缓存算法:在Glide中使用BitmapPool来缓存Bitmap,使用的也是LRU算法(最近最少使用算法),当需要使用Bitmap时,先从Bitmap的池子中选取,如果找不到合适的Bitmap,再去创建,当使用完毕后,不再直接调用Bitmap.recycle()释放内存,而是缓存到Bitmap池子里。
    
    Bitmap的缓存是以键值对的方式进行缓存的,Resource和Bitmap都作为Value,而这些值是需要一个key来标识缓存的内容,根据key可以查找和移除对应的缓存。
    
    

    相关文章

      网友评论

          本文标题:Glide源码分析

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