• Glide万字解密


    Glide现在应用最广的一个图片加载框架了,一直都想对它下手,每次都是深陷其中。。。这次狠下心来,对它来个全面的剖析,争取对整个流程和其中的细节都有一个覆盖。

    本文的Glide的解析是基于最新的4.11.0版本来进行的。

    其实从一般的网络加载图片,可以简单分析下大体的流程,无非就是建立相关的请求信息,然后通过线程池技术对请求信息进行请求,然后将下载的图片文件进行转化显示。

    先来看个简单的测试使用代码开始,然后逐步深入

    Glide.with(view.getContext())
                    .load(url)
                    .into(view);
    

    with()

    Glide的with函数为我们提供了不同的入参,其最终的返回对象都是 RequestManager

    image-20200213095828075

    我们的测试代码用的是 Context 那么这里我们就跟踪一下这个函数,其实其他几个都是相似的

      @NonNull
      public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
      }
      
     @NonNull
      private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        //校验Context不能为空
        Preconditions.checkNotNull(context,"....");
        return Glide.get(context).getRequestManagerRetriever();
      }
      //直接获取Glide对象的requestManagerRetriever属性
      public RequestManagerRetriever getRequestManagerRetriever() {
        return requestManagerRetriever;
      }
    
    

    可以看到 RequestManagerRetriever 对象的创建,肯定是在 Glide.get() 中进行了处理

      //通过双重加锁单例方法,创建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对象
      @GuardedBy("Glide.class")
      private static void checkAndInitializeGlide(
          @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
        // In the thread running initGlide(), one or more classes may call Glide.get(context).
        // Without this check, those calls could trigger infinite recursion.
        if (isInitializing) {//如果正在创建,则直接报错
          throw new IllegalStateException(
              "You cannot call Glide.get() in registerComponents(),"
                  + " use the provided Glide instance instead");
        }
        isInitializing = true;
        //真正的创建方法
        initializeGlide(context, generatedAppGlideModule);
        isInitializing = false;
      }
      //初始化Glide
      @GuardedBy("Glide.class")
      private static void initializeGlide(
          @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
        initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
      }
    
      @GuardedBy("Glide.class")
      @SuppressWarnings("deprecation")
      private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder, @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
        ...
        //创建了RequestManagerFactory工厂对象,用来创建对应的RequestManager
        RequestManagerRetriever.RequestManagerFactory factory =
            annotationGeneratedModule != null
                ? annotationGeneratedModule.getRequestManagerFactory()
                : null;
        builder.setRequestManagerFactory(factory);
        ...
        //建造者设计模式,创建Glide对象
        Glide glide = builder.build(applicationContext);
        ...
        applicationContext.registerComponentCallbacks(glide);
        Glide.glide = glide;
      }
    

    可以看到,这里使用建造者设计模式,来创建了 glide 对象。在 builder 中设置了一个 RequestManagerFactory 的属性。看下在builder中,具体帮我们做了什么工作。

      @NonNull
      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) {//bitmap池
          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) {//内存缓存策略,默认使用Lru缓存策略
          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) {//请求监听器,是一个不可变的List
          defaultRequestListeners = Collections.emptyList();
        } else {
          defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
        }
        //这里创建了一个RequestManagerRetriever对象,参数是之前设置的Factory对象
        RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);
        return new Glide(//创建Glide对象
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptionsFactory,
            defaultTransitionOptions,
            defaultRequestListeners,
            isLoggingRequestOriginsEnabled,
            isImageDecoderEnabledForBitmaps);
      }
    

    GlideBuilder 中,帮我们创建了很多的对象,包括线程池、缓存器、缓存大小、Engine、RequestManagerRetriever。

    因为我们在调用 with() 方法时,使用了 requestManagerRetriever ,我们这里去看一眼,里面有没有做什么特殊处理

    public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
      this.factory = factory != null ? factory : DEFAULT_FACTORY;
      handler = new Handler(Looper.getMainLooper(), this /* Callback */);
    }
    
    private static final RequestManagerFactory DEFAULT_FACTORY =
          new RequestManagerFactory() {
            @NonNull
            @Override
            public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
              return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
            }
          };
    

    很简单的构造函数,里面创建了 handler对象,并设置了 RequestManagerFactory 对象。

    回到主干,看看Glide的构造函数。

      Glide(
          @NonNull Context context,
          @NonNull Engine engine,
          @NonNull MemoryCache memoryCache,
          @NonNull BitmapPool bitmapPool,
          @NonNull ArrayPool arrayPool,
          @NonNull RequestManagerRetriever requestManagerRetriever,
          @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
          int logLevel,
          @NonNull RequestOptionsFactory defaultRequestOptionsFactory,
          @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
          @NonNull List<RequestListener<Object>> defaultRequestListeners,
          boolean isLoggingRequestOriginsEnabled,
          boolean isImageDecoderEnabledForBitmaps) {
        this.engine = engine;
        this.bitmapPool = bitmapPool;
        this.arrayPool = arrayPool;
        this.memoryCache = memoryCache;
        this.requestManagerRetriever = requestManagerRetriever;
        this.connectivityMonitorFactory = connectivityMonitorFactory;
        this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
    
        final Resources resources = context.getResources();
        //注册机,里面维护了编码、解码、加载、图片请求头、支持的图片等的各种注册表信息
        registry = new Registry();
        registry.register(new DefaultImageHeaderParser());
        registry
            .append(int.class, InputStream.class, resourceLoaderStreamFactory)
            .......
        ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
        glideContext =
            new GlideContext(//创建glideContext对象
                context,
                arrayPool,
                registry,
                imageViewTargetFactory,
                defaultRequestOptionsFactory,
                defaultTransitionOptions,
                defaultRequestListeners,
                engine,
                isLoggingRequestOriginsEnabled,
                logLevel);
      }
    

    这里面将一些属性赋值,并且创建了 GlideContext 对象,以及registry对象。

    到此为止,我们的Glide单例对象创建完成了....

    RequestManger对象的获取

    public static RequestManager with(@NonNull Context context) {
      return getRetriever(context).get(context);
    }
    

    在获取到 RequestManagerRetriever 对象以后,通过 get 方法来获取到 RequestManager 对象,我们现在来跟踪一下代码的实现。

      @NonNull
      public RequestManager get(@NonNull Context context) {
        if (context == null) {//context为空抛异常
          throw new IllegalArgumentException("You cannot start a load on a null Context");
        } else if (Util.isOnMainThread() && !(context instanceof Application)) {
          //如果当前线程是主线程,并且context不是Application,那么对应的生命周期是和UI(Activity或者Fragment)进行绑定的,
          //通过创建隐藏Fragment的方法来监听context的生命周期。然后将RequestManager和Fragment来绑定。
          //因为v4和普通的Fragment中创建Fragment的方式是不同的,所以这里根据不同的context类型,来进行不同的处理
          if (context instanceof FragmentActivity) {//如果是FragmentActivity
            return get((FragmentActivity) context);
          } else if (context instanceof Activity) {//如果是普通的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());
          }
        }
        //返回应用RequestManager
        return getApplicationManager(context);
      }
    

    在get()方法中,根据Context的类型的不同,来进行了不同的处理。我们这里跟踪一个 FragmentActivity 类型的,其他的是相似的

      @NonNull
      public RequestManager get(@NonNull FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {//如果是后台线程,则context按照application处理,即和UI的生命周期解绑
          return get(activity.getApplicationContext());
        } else {
          //在UI线程进行处理
          assertNotDestroyed(activity);//判断activity是否被销毁了
          FragmentManager fm = activity.getSupportFragmentManager();
          return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
        }
      }
      //获取FragmentManager所管理的RequestManager
      private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint,
          boolean isParentVisible) {
        //创建一个隐形的SupportRequestManagerFragment,来监听对应的Context的生命周期
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
        //获取Fragment中对应的请求管理器,(每个Fragment只有一个唯一的请求管理器)
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {//如果当前没有设置过请求管理器,那么创建并设置
          Glide glide = Glide.get(context);
          //通过工厂方法,创建requestManager对象
          requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    

    实际的 RequestManager 是通过factory来构建的

    RequestManager(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode,
        RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) {
      this.glide = glide;
      this.lifecycle = lifecycle;
      this.treeNode = treeNode;
      this.requestTracker = requestTracker;
      this.context = context;
      //连接监听器
      connectivityMonitor = factory
          .build(context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker));
      if (Util.isOnBackgroundThread()) {
        mainHandler.post(addSelfToLifecycle);
      } else {
        lifecycle.addListener(this);
      }
      lifecycle.addListener(connectivityMonitor);
      defaultRequestListeners =
          new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
      //设置请求配置信息
      setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
      //将RequestManager注册到全局glide中
      glide.registerRequestManager(this);
    }
    

    到现在为止,我们已经对于创建了 RequestManager ,那么后续就是其调用 load() 方法了。

    load()

    RequestManager 支持对多种参数形式的图片加载:

    image-20200213163514155

    我们从我们的案例跟踪,传入的参数是String类型。

    //相当于先调用了asDrawable(),然后调用了load()方法
      public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
        return asDrawable().load(resourceId);
      }
    
      public RequestBuilder<Drawable> asDrawable() {
        return as(Drawable.class);
      }
    
      //创建能够解码对应类型的图片的RequestBuilder
      public <ResourceType> RequestBuilder<ResourceType> as(
          @NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder<>(glide, this, resourceClass, context);
      }
    

    我们看下 RequestBuilder 的构造方法做了什么处理

      protected RequestBuilder(@NonNull Glide glide, RequestManager requestManager, 
          Class<TranscodeType> transcodeClass, Context context) {
        this.glide = glide;
        this.requestManager = requestManager;
        this.transcodeClass = transcodeClass;
        this.context = context;
        //这里的transcodeClass大概率是Drawable类对象
        this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
        this.glideContext = glide.getGlideContext();
    
        initRequestListeners(requestManager.getDefaultRequestListeners());
        apply(requestManager.getDefaultRequestOptions());
      }
    

    在创建完RequestBuilder对象之后,直接调用了 RequestBuilderload() 方法。

      public RequestBuilder<TranscodeType> load(@Nullable String string) {
        return loadGeneric(string);
      }
      
      private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        this.model = model;
        isModelSet = true;
        return this;
      }
    

    这里也没有进行特殊的操作,只是将 isModelSet 设置为了true,标记model已经进行了设置。

    into()

    with()load() 方法中,主要是进行了一些前期的准备工作。真正执行图片的加载、缓存、转化到View上等等这些操作,都是在 into() 中执行的。

      public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        Util.assertMainThread();//方法需要在主线程执行
        Preconditions.checkNotNull(view);//view不能为空
        BaseRequestOptions<?> requestOptions = this;
        if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {//根据View上配置的scaleType,设置requestOptions
          switch (view.getScaleType()) {
            case CENTER_CROP:
              requestOptions = requestOptions.clone().optionalCenterCrop();
              break;
          }
        }
        return into(glideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null, 
            requestOptions,
            Executors.mainThreadExecutor());
      }
    

    这里根据设置的信息配置 requestOptions 相关参数,然后调用了 buildImageViewTarget 方法,构造了一个 viewTarget 对象。

    我们现在看一下这个方法

      @NonNull
      public <X> ViewTarget<ImageView, X> buildImageViewTarget(
          @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
        //通过工厂方法创建ViewTarget对象,这里一般返回的是DrawableImageViewTarget,如果是使用了asBitmap那么返回的是BitmapImageViewTarget
        return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
      }
      
    public class ImageViewTargetFactory {
      public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) {
        if (Bitmap.class.equals(clazz)) {//如果使用了asBitmap方法,那么这里的clazz回事bitmap
          return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
        } else if (Drawable.class.isAssignableFrom(clazz)) {//如果只是正常的使用,一般会返回DrawableImageViewTarget
          return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
        } else {
          throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
        }
      }
    }
    

    可以看到这里,大部分情况下返回的是一个 DrawableImageViewTarget 对象信息,

    回到主线。继续

      private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener,
          BaseRequestOptions<?> options, Executor callbackExecutor) {
        Preconditions.checkNotNull(target);
        if (!isModelSet) {//如果model没有进行设置(没有调用load方法会导致这种情况的方法),直接报错。
          throw new IllegalArgumentException("You must call #load() before calling #into()");
        }
        //创建一个request请求
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
        //获取target上是否已经存在了相应的请求,如果存在,则进行清空处理
        Request previous = target.getRequest();
        if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          //target上标记点的请求和生成的请求相同,直接启动相应的请求,然后返回target对象
          if (!Preconditions.checkNotNull(previous).isRunning()) {
            previous.begin();
          }
          return target;
        }
        //将原有的target从请求管理类requestManager中移除掉
        requestManager.clear(target);
        //将新的请求设置进target
        target.setRequest(request);
        //requestManager开启对于target和request的跟踪处理(主要是启动请求,并且将请求类和target进行统一管理)
        requestManager.track(target, request);
        return target;
      }
    

    这段代码是Glide的核心,里面进行了 Request 请求对象的创建以及执行。

    请求对象的创建过程

    我们先看下 Request 请求对象的创建过程: 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);
      }
      
      //创建请求类,分为处理错误显示的请求和正常显示的请求
      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) {
        .....
        Request mainRequest =//正常显示的请求
            buildThumbnailRequestRecursive(requestLock, target, targetListener, parentCoordinator, transitionOptions,
                priority, overrideWidth, overrideHeight, requestOptions, callbackExecutor);
        ...
        return errorRequestCoordinator;
      }
    

    这个函数将请求进行了分类,一种是错误显示的请求信息,一种是正常显示的请求信息。

    我们看一下正常显示的请求处理函数中,是如何创建的。

      //生成处理正常显示的请求,会根据相关的设置,创建缩略图或者原图
      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) {//存在缩略图生成器,根据builder信息创建缩略图请求
          ...
        } else if (thumbSizeMultiplier != null) {//存在图片放大缩小指数,则根据指数信息创建缩略图请求
          ...
        } else {
          //一般会通过这个方法进行处理
          return obtainRequest(requestLock, target, targetListener, requestOptions, parentCoordinator,
              transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor);
        }
      }
    

    这个代码段很长,我们进行了省略,里面大部分都是对于生成缩略图请求的一些特殊处理。后面我们有机会再分析。我们主要看一下 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 对象,并且把相关参数进行了赋值,里面并没有什么特殊的处理。

    到此为止,我们的 Request 已经创建完成了。下一步就是看一下,是如何进行网络请求的。

    请求的执行

    回到原来的 into() 代码块中,这次我们跟踪的是 requestManager.track(target, request) 这个函数

      synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
        //target管理类,里面通过set列表方式保存了所有的target信息,并且实现了生命周期接口,能够根据生命周期,启动或者暂停target的动画
        targetTracker.track(target);
        //requestTracker管理类,里面通过set列表方式保存了所有的request信息,通过runRequest方法,将请求保存到set列表,并启动请求
        requestTracker.runRequest(request);
      }
      //启动并跟踪请求
      public void runRequest(@NonNull Request request) {
        requests.add(request);//保存到set列表
        if (!isPaused) {//加载处于可用状态,直接调用begin()
          request.begin();
        } else {//加载处于暂停状态,将request请求保存起来的,等可以状态时,从列表里面逐个启动
          request.clear();
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Paused, delaying request");
          }
          //将请求放到pendingRequests,因为requests是弱引用,防止被回收
          pendingRequests.add(request);
        }
      }
    

    这里就是个简单的处理,如果当前的 RequestManager 处于可用状态(即绑定的Context是处于可见的),那么就直接进行任务的请求处理。否则将请求放到 pendingRequests 所对应的的set列表中,虽然 requests中已经保存了对应的请求信息,但是由于其是弱引用,所以存在会被回收的情况,所以使用了pendingRequests来进行保存。

    在创建请求对象的分析中,我们知道最后创建的是 SingleRequest 对象,继续 begin() 方法的跟踪

     public void begin() {
        synchronized (requestLock) {
          assertNotCallingCallbacks();
          stateVerifier.throwIfRecycled();
          startTime = LogTime.getLogTime();
          if (model == null) {//如果加载的图片源(url,file等)为null,则直接onLoadFailed
            ...
            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接口
            //如果我们重新启动后完成(通常是通过一个notifyDataSetChanged将一个相同的请求开始到相同的目标或视图),
            //我们可以简单地使用资源和大小,而不需要获得一个新的尺寸,开始一个新的加载等。
            // 这确实意味着,如果客户确实需要重新加载,那么需要在加载之前,显示的调用clear清除视图或目标。
            onResourceReady(resource, DataSource.MEMORY_CACHE);
            return;
          }
          status = Status.WAITING_FOR_SIZE;
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            //如果要加载的视图的宽和高已经固定,直接进行加载
            onSizeReady(overrideWidth, overrideHeight);
          } else {
            //设置回调信息,当视图的宽高完成以后,进行回调处理。通过target(Target类,里面包含要了View的信息)的getViewTreeObserver方法,来监听控件的绘制,从而能够获取到对应的宽高,最后通过接口回调调用onSizeReady(width,height)方法
            target.getSize(this);
          }
          if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
              && canNotifyStatusChanged()) {
            //设置PlaceholderDrawable这些信息,然后去后台加载资源,最后将对应的数据显示在target上面
            target.onLoadStarted(getPlaceholderDrawable());
          }
          if (IS_VERBOSE_LOGGABLE) {
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
          }
        }
      }
    

    begin() 函数中最主要的是通过View宽高已知(不论是已经固定还是通过绘制后的回调)的情况下,调用 onSizeReady 方法来执行具体的加载过程。而且在加载未完成的情况下,在View上设置了对应的占位图(也就是我们经常在代码里面使用的 .placeholder() 方法)。

      public void onSizeReady(int width, int height) {
        stateVerifier.throwIfRecycled();
        synchronized (requestLock) {
          ...
          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);
           ...
        }
      }
    

    函数最终是通过调用了 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(//根据相关参数创建一个key值
                model,
                signature,
                width,
                height,
                transformations,
                resourceClass,
                transcodeClass,
                options);
    
        EngineResource<?> memoryResource;
        synchronized (this) {
          //从内存加载
          memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
          if (memoryResource == null) {
            //如果在内存中没有查询到,那么内部创建一个Job并进行执行,返回LoadStatus
            return waitForExistingOrStartNewJob(
                glideContext,
                model,
                signature,
                width,
                height,
                resourceClass,
                transcodeClass,
                priority,
                diskCacheStrategy,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                options,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache,
                cb,
                callbackExecutor,
                key,
                startTime);
          }
        }
    

    我们都知道,现有的任何一个图片加载框架都使用了缓存来进行数据的处理,以此来加快图片的加载速度。Glide 也不例外,从代码可以看到对于资源的加载。

    通过相关的参数生成了一个key

    1. 通过key在内存查找
    2. 如果查找到了,那么直接通过接口回调来返回资源信息。
    3. 如果没有,则会创建新的任务请求来加载。

    我们先从内存加载函数 loadFromMemory() 来分析一下是如何处理的。

      private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
        if (!isMemoryCacheable) {//如果不允许在缓存加载,直接返回  通过.skipMemoryCache(false)来关闭缓存功能
          return null;
        }
        //从正在使用的图片列表中获取
        EngineResource<?> active = loadFromActiveResources(key);
        if (active != null) {
          return active;
        }
        //从MemoryCache(这里使用的一般是LurMemoryCache)中获取
        EngineResource<?> cached = loadFromCache(key);
        if (cached != null) {
          return cached;
        }
        return null;
      }
    
      //从正在使用的资源中加载的
      private EngineResource<?> loadFromActiveResources(Key key) {
        //从已经被加载的资源中获取
        EngineResource<?> active = activeResources.get(key);
        if (active != null) {//占用资源的计数器+1
          active.acquire();
        }
        return active;
      }
      //从cache中获取
      private EngineResource<?> loadFromCache(Key key) {
        //从Cache中获取
        EngineResource<?> cached = getEngineResourceFromCache(key);
        if (cached != null) {
          //如果缓存中存在,则从缓存中移除,并放入到正在使用的Resource列表中
          cached.acquire();
          activeResources.activate(key, cached);
        }
        return cached;
      }
    
    

    源码相对来说比较简单。

    1. loadFromActiveResources() 先从正在使用的资源中去查找。如果查找到,将资源的引用计数器+1,返回资源文件。
    2. 如果没有查找到,则从缓存中获取,缓存默认使用的LruMemoryCache(可以使用)。如果获取成功,则从缓存中移除,并放置到activeResources中(强引用)。防止缓存被回收导致的资源失效。
    3. 如果仍然没有,则整个函数返回null

    如果最终没有从内存获取到资源文件,那么代码会通过 waitForExistingOrStartNewJob 来执行资源的加载。

      //使用已有的Job或者创建新的Job来进行资源加载
      private <R> LoadStatus waitForExistingOrStartNewJob(...) {
        //从在执行的jobs列表中查询,onlyRetrieveFromCache为仅从缓存加载图片标志位。
        EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
        if (current != null) {
          //如果存在,则为当前任务增加一个回调接口,
          //可能一个资源在多个地方同时使用的情况,因此,加载完成后,需要回调多个接口来进行通知
          current.addCallback(cb, callbackExecutor);
          return new LoadStatus(cb, current);
        }
        //创建一个EngineJob
        EngineJob<R> engineJob =engineJobFactory.build(...);
        //负责从缓存的数据资源或者原始资源获取数据,是数据的获取类
        DecodeJob<R> decodeJob =decodeJobFactory.build(...);
        //将engineJob存放到jobs,engineJob中有onlyRetrieveFromCache的字段,所以可以根据该字段放置到不同的list中
        jobs.put(key, engineJob);
        //增加回调接口
        engineJob.addCallback(cb, callbackExecutor);
        //启动engineJob去加载资源
        engineJob.start(decodeJob);
        return new LoadStatus(cb, engineJob);
      }
    
    

    我们这里只关心新建 EngineJob 并执行加载的过程,所以这里我们主要看一下 engineJob.start(decodeJob) 的执行

      public synchronized void start(DecodeJob<R> decodeJob) {
        this.decodeJob = decodeJob;
        //根据decodeJob的设置,使用不存的执行器
        GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
        //启动decodeJob,decodeJob实现了Runnable接口,会调用其run()方法
        executor.execute(decodeJob);
      }
    

    我们现在看看DecodeJob的run方法

      @Override
      public void run() {
        DataFetcher<?> localFetcher = currentFetcher;
        try {
          if (isCancelled) {//如果已经取消了,则直接返回失败。isCancelled是volatile。保证了多线程的可见性
            notifyFailed();//通知上层(EngineJob)调用失败,并且进行相关资源的回收工作
            return;
          }
          //主要的加载函数
          runWrapped();
        } catch (CallbackException e) {
          //如果已经进入了encode阶段时,我们已经调用了callback上层接口,这时候需要通过调用失败接口来进行资源释放,否则是不安全的
          // 可以查看notifyEncodeAndRelease(Resource, DataSource)方法里面
          if (stage != Stage.ENCODE) {
            throwables.add(t);
            notifyFailed();
          }
          throw t;
        } finally {
          if (localFetcher != null) {//进行localFetcher的清理工作,因为DecodeJob是进行复用的。
            localFetcher.cleanup();
          }
          GlideTrace.endSection();//记录整个Glide的跟踪记录信息
        }
      }
    

    run 方法只有一个最主要的函数,就是 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 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);
        }
      }
      /**
       * 根据当前状态,返回下一个状态。由于diskCacheStrategy默认的使用AUTOMATIC的缓存策略,
       * decodeCachedResource()和decodeCachedData()返回的都是true
       * 下一个阶段图:
       * 初始化->资源缓存解码->数据缓存->源->结束
       *
       */
      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:
            return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
          case SOURCE:
          case FINISHED:
            return Stage.FINISHED;
          default:
            throw new IllegalArgumentException("Unrecognized stage: " + current);
        }
      }
    

    Glide的资源加载的主要流程依次为

    1. 资源缓存解码
    2. 数据缓存
    3. 数据源源

    其对应的数据加载类为:

    1. ResourceCacheGenerator :从缓存文件加载数据(包括了向下采样/转化后的资源)
    2. DataCacheGenerator :从数据缓存加载数据(原始的缓存资源)
    3. 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;
          }
        }
        if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {//如果已经结束或者取消了,直接回调失败
          notifyFailed();
        }
      }
    

    在该函数里面,通过while循环来遍历执行相关的数据加载器,直到所有的数据加载器都执行完,或者某个加载器加载到了相关的数据。

    ResourceCacheGenerator#startNext

    我们先看看 ResourceCacheGenerator 是如何执行加载过程的。

     public boolean startNext() {
        //每种model都对应着多个解析器,最后根据model的格式(String,Uri等),来找到可以使用的LoadData列表。每个LoadData都会存在一个对应的key。
        //这里获取了对应的key列表
        List<Key> sourceIds = helper.getCacheKeys();//如果model没有对应的映射出来的key。则直接返回false
        if (sourceIds.isEmpty()) {
          return false;
        }
        //获取由model转化为resource的类,也即是可以decode的资源类信息
        List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
        if (resourceClasses.isEmpty()) {
          if (File.class.equals(helper.getTranscodeClass())) {
            return false;
          }
          throw new IllegalStateException(
              "Failed to find any load path from "
                  + helper.getModelClass()
                  + " to "
                  + helper.getTranscodeClass());
        }
        while (modelLoaders == null || !hasNextModelLoader()) {//双层遍历
          resourceClassIndex++;
          if (resourceClassIndex >= resourceClasses.size()) {
            sourceIdIndex++;
            if (sourceIdIndex >= sourceIds.size()) {
              return false;
            }
            resourceClassIndex = 0;
          }
          Key sourceId = sourceIds.get(sourceIdIndex);
          Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
          Transformation<?> transformation = helper.getTransformation(resourceClass);se.
          currentKey =
              new ResourceCacheKey( // NOPMD Avoid Instantiating Objects InLoops
                  helper.getArrayPool(),
                  sourceId,
                  helper.getSignature(),
                  helper.getWidth(),
                  helper.getHeight(),
                  transformation,
                  resourceClass,
                  helper.getOptions());
          //根据当前的key获取缓存的文件
          cacheFile = helper.getDiskCache().get(currentKey);
          if (cacheFile != null) {//获取到缓存文件了,设置对应的modelLoader和key,而且会跳出循环
            sourceKey = sourceId;
            modelLoaders = helper.getModelLoaders(cacheFile);
            modelLoaderIndex = 0;
          }
        }
        loadData = null;
        boolean started = false;
        while (!started && hasNextModelLoader()) {
          ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
          loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
          if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
            //有对应的LoadData
            started = true;
            //通过fetcher去加载对应的文件
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    我们总结一下大体的流程:

    1. 根据传入的参数,获取对应的 sourceIdsresourceClasses
    2. 正交遍历,迭代每一组。根据相关参数生成在缓存文件使用的key,然后根据key去查询是否有缓存文件
    3. 如果查找到对应的缓存文件,则设置sourceKey 和modelLoaders。然后通过这两个的设置可以跳出循环。
    4. modeLoaders 遍历,获取 modelLoader ,并创建对应的 loadData
    5. 如果 LoadData 存在,并且其内部的 dataFatcher (数据读取器)获取的数据类存在,则设置started标志位,表明该从 ResourceCacheGenerator 已经加载到相关数据了(这样后面所有的加载器都不再执行)。然后通过dataFatcher去获取数据。
    6. 如果遍历没有加载相关数据,则返回started标志位为false。表明 ResourceCacheGenerator 没有加载到相关资源。之后的 加载器(DataCacheGenerator,也可能是SourceGenerator,也可能是跳出循环,根据之前讲的相应设置有关) 会继续执行。

    如果第一次加载,那么在 DataCacheGenerator 中,肯定是获取不到资源的,那么下一个会执行到 DataCacheGeneratorstartNext() 方法

    DataCacheGenerator#startNext

      @Override
      public boolean startNext() {
        while (modelLoaders == null || !hasNextModelLoader()) {
          sourceIdIndex++;
          if (sourceIdIndex >= cacheKeys.size()) {
            return false;
          }
          //获取源资源的Key信息
          Key sourceId = cacheKeys.get(sourceIdIndex);//cacheKeys=helper.getCacheKeys()
          //根据当前sourceId,获取对应的原始Key。
          Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
          //根据原始的Key从磁盘缓存获取缓存文件,并且跳出循环
          cacheFile = helper.getDiskCache().get(originalKey);
          if (cacheFile != null) {
            this.sourceKey = sourceId;
            modelLoaders = helper.getModelLoaders(cacheFile);
            modelLoaderIndex = 0;
          }
        }
        loadData = null;
        boolean started = false;
        while (!started && hasNextModelLoader()) {
          ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
          loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
          if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
            //有对应的LoadData
            started = true;
            //通过fetcher去加载对应的文件
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    DataCacheGenerator 主要是获取原始的缓存文件。可以看到大体的流程是和 ResourceCacheGenerator 相似的。唯一的不同是,获取的Key不一样。在获取缓存文件的时候,使用的参数是 DataCacheKey ,也就是原始缓存文件的键值。

    在首次进行加载的时候,这个肯定也是获取不到的,返回的是空,那么这时候,那么下一个会执行到 SourceGeneratorstartNext() 方法。

    SourceGenerator#startNext

      public boolean startNext() {
        if (dataToCache != null) {
          //当第一次资源加载完成以后,会进行一次线程切换,而再次调用本方法,这时候dataToCache不为空,然后进行data的保存,此地是磁盘缓存源文件
          // 并且生成了DataCacheGenerator类
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
        }
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          //在有DataCacheGenerator类的情况下,会调用startNext方法,执行从源文件的加载文件
          return true;
        }
        sourceCacheGenerator = null;
        loadData = null;
        boolean started = false;
        while (!started && hasNextModelLoader()) {
          //循环获取当前model相关的所有的modelLoaders,获取loadData数据
          loadData = helper.getLoadData().get(loadDataListIndex++);
          //这里需要注意,假如缓存策略认为可以缓存data,那么就不需要管后面的loadPath,直接先把data获取。
          //因为缓存之后将会移交给DataCacheGenerator处理,所以可以跳过后面的hasLoadPath判断。
          //hasLoadPath是根据Registry中已经注册的解码器,转换器判断是否可以完成dataclass->resourceclass->transcodeclass的变换。
          if (loadData != null &&
              (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
                  || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
            started = true;
            startNextLoad(loadData);
          }
        }
        return started;
      }
    
      private void startNextLoad(final LoadData<?> toStart) {
        loadData.fetcher.loadData(//进行资源的加载
            helper.getPriority(),
            new DataCallback<Object>() {
              @Override
              public void onDataReady(@Nullable Object data) {
                if (isCurrentRequest(toStart)) {
                  onDataReadyInternal(toStart, data);
                }
              }
    
              @Override
              public void onLoadFailed(@NonNull Exception e) {
                if (isCurrentRequest(toStart)) {
                  onLoadFailedInternal(toStart, e);
                }
              }
            });
      }
    

    当进行资源加载完成以后,会通过回调 onDataReady 接口。我们看一下 onDataReadyInternal 的执行。

     @Synthetic
      void onDataReadyInternal(LoadData<?> loadData, Object data) {
        DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
        if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
          //如果DataFetcher对应的DataSource可以进行缓存
          dataToCache = data;
          //这里的cb,指的是DecodeJob类->callback.reschedule(this),callback指的是EngineJob类
          //->getActiveSourceExecutor().execute(job);
          //即通过线程池,重新执行了EngineJob,然后会执行到本类的startNext方法,因为dataToCache不为空,会执行里面的代码块
          cb.reschedule();
        } else {
          //如果不能进行缓存,则直接调用onDataFetcherReady方法
          cb.onDataFetcherReady(
              loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), originalKey);
        }
      }
    

    我们先分析第一种情况。

    我们注释写的很详细了,也知道最后会重新调用本类的 startNext 方法,那么我们看看这个方法开始的部分。

        if (dataToCache != null) {
          //当第一次资源加载完成以后,会进行一次线程切换,而再次调用本方法,这时候dataToCache不为空,然后进行data的保存,此地是磁盘缓存源文件
          // 并且生成了DataCacheGenerator类
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
        }
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          //在有DataCacheGenerator类的情况下,会调用startNext方法,执行从源文件的加载文件
          return true;
        }
       
      private void cacheData(Object dataToCache) {
        long startTime = LogTime.getLogTime();
        try {
          //获取到编码器,通过遍历注册表中编码器列表,获取到对应的cache类的编码器
          Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
          //生成
          DataCacheWriter<Object> writer = new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
          //生成原始缓存文件的key,用于进行DataCacheGenerator中进行编码查找
          originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
          //通过DiskCache进行数据的缓存
          helper.getDiskCache().put(originalKey, writer);
        } finally {
          loadData.fetcher.cleanup();
        }
    
        sourceCacheGenerator =
            new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
      }
    

    也就是先在磁盘上保存原文件,然后通过DataCacheGenerator类再去进行加载。

    现在我们看第二种情况:

      public void onDataFetcherReady(
          Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
        ...
        if (Thread.currentThread() != currentThread) {
          //设置执行原因为DECODE_DATA,再重新调用unwrapper时,就可以直接执行解码阶段了。也就是下面else中的decodeFromRetrievedData方法
          runReason = RunReason.DECODE_DATA;
          callback.reschedule(this);
        } else {
          GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            decodeFromRetrievedData();
          } finally {
            GlideTrace.endSection();
          }
        }
      }
    

    这时候会根据线程进行一次重新调用,或者直接调用 decodeFromRetrievedData() 方法。

     //解码检索到的的数据
      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) {
          //通过接口回调资源加载成功接口,然后进行层层回调由DecodeJon->EngineJob->Target中,最后由Target操作ImageView,将资源渲染到View上
          notifyEncodeAndRelease(resource, currentDataSource);
        } else {
          runGenerators();
        }
      }
    

    大体的流程基本完成了。后续再对细节一点点进行增加。

    补充几个文件:

    ModelLoader(资源加载类):包含两个方法

    buildLoadData():创建LoadData类

    handles(Model):该类能否能够加载给定的模型

    LoadData类:包含了3个属性

    sourceKey:资源key

    alternateKeys:临时key的列表

    fetcher:持有的一个DataFetcher接口实例,定义了真正获取数据的loadData方法

    DataFetcher接口:真正的资源获取

    loadData():获取能够被解码的数据

    cleanup():清空或者回收资源

    getDataClass():当前实现类能获取的资源的类

    getDataSource():此fetcher将从哪种数据源返回数据,枚举类型。

  • 相关阅读:
    hdu 1875 畅通project再续(kruskal算法计算最小生成树)
    Http post提交和get提交
    我的软考之路(五)——数据结构与算法(3)之图
    WPF 布局控件 之 DockPanel
    oracle存储结构
    马化腾最想做的事情是人工智能
    Android_Zip解压缩工具
    Unity的 Stats 窗体, Batched、SetPass、Draw Call 等
    尝试 “实验楼”在线教育平台
    POJ 3181 Dollar Dayz 01全然背包问题
  • 原文地址:https://www.cnblogs.com/kailaisii/p/12322971.html
Copyright © 2020-2023  润新知