Glide 源码解析

源码方面主要从最基本的三个方法入手:with,load,into。

Glide.with

Glide.with()方法根据不同上下文对象有多个重载方法,源码如下:

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

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

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

public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
}

public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
}

public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
}

可以看到,每个重载方法内部都首先调用getRetriever()方法获取一个RequestManagerRetriever对象,然后调用其get方法来返回RequestManager。

传入getRetriever()的参数都是Context,而RequestManagerRetriever.get()方法传入的参数各不相同,所以生命周期的绑定肯定发生在get方法中。

下面,接着分析getRetriever()方法。

getRetriever(Context)

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    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();
}

因入参context为fragment.getActivity()时,context可能为空,所以这里进行了一次判断。然后就调用了Glide.get(context)创建了一个Glide,最后将requestManagerRetriever返回即可。

获取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;
}

private static void checkAndInitializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    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;
}

private static void initializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}

private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    Context applicationContext = context.getApplicationContext();
    ...
    // 调用GlideBuilder.build方法创建Glide
    Glide glide = builder.build(applicationContext);
    ...
    // 注册内存管理的回调,因为Glide实现了ComponentCallbacks2接口
    applicationContext.registerComponentCallbacks(glide);
    // 保存glide实例到静态变量中
    Glide.glide = 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) {
        // 使用缓存,则创建bitmap对象池
        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();
    //创建请求管理类,其构造方法中会实例化一个主线程的handler对象,用于线程的切换
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory, experiments);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        experiments);
}

这里的requestManagerRetriever直接调用了构造器,且传入参数实际上为null,在RequestManagerRetriever的构造器方法中会为此创建一个默认的DEFAULT_FACTORY。

public RequestManagerRetriever(
      @Nullable RequestManagerFactory factory, GlideExperiments experiments) {
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);
    frameWaiter = buildFrameWaiter(experiments);
}

目前为止,Glide单例已经被创建出来了,其requestManagerRetriever会作为getRetriever(Context)的返回值返回。

RequestManagerRetriever.get系列方法

RequestManagerRetriever类的get方法,会有相关重载方法。

public class RequestManagerRetriever implements Handler.Callback {
    ....
    
/** The top application level RequestManager. */
  private volatile RequestManager applicationManager;
  
private final RequestManagerFactory factory;

@NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          // Normally pause/resume is taken care of by the fragment we add to the fragment or
          // activity. However, in this case since the manager attached to the application will not
          // receive lifecycle events, we must force the manager to start resumed using
          // ApplicationLifecycle.

          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }
  
@NonNull
  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);
  }
  
@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
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(
        fragment.getContext(),
        "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getContext().getApplicationContext());
    } else {
      // In some unusual cases, it's possible to have a Fragment not hosted by an activity. There's
      // not all that much we can do here. Most apps will be started with a standard activity. If
      // we manage not to register the first frame waiter for a while, the consequences are not
      // catastrophic, we'll just use some extra memory.
      if (fragment.getActivity() != null) {
        frameWaiter.registerSelf(fragment.getActivity());
      }
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
    }
  }
  
 @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else if (activity instanceof FragmentActivity) {
      return get((FragmentActivity) activity);
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  
@NonNull
  public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(
        view.getContext(), "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    // Support Fragments.
    // Although the user might have non-support Fragments attached to FragmentActivity, searching
    // for non-support Fragments is so expensive pre O and that should be rare enough that we
    // prefer to just fall back to the Activity directly.
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get((FragmentActivity) activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  } 
 
}

从上面一系列get()重载方法,方法内部会首先判断当前线程是不是后台线程,如果是后台线程最终会调用getApplicationManager()方法返回RequestManager;

如果当前线程不是后台线程,get(Context)方法根据情况会调用get(FragmentActivity)、get(Activity)、getApplicationManager(context)方法;get(View)方法根据情况会调用get(Fragment)、get(Activity)方法;get(Fragment)和get(FragmentActivity)方法都会调用supportFragmentGet方法。

Glide会使用一个加载目标所在的宿主Activity或Fragment的子Fragment来安全保存一个RequestManager,而RequestManager被Glide用来开始、停止、管理Glide请求。而supportFragmentGet就是创建/获取这个SupportRequestManagerFragment,并返回其持有的RequestManager的方法。

private final RequestManagerFactory factory;

final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
      new HashMap<>();

 @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    // 获取一个SupportRequestManagerFragment  
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    // 获取里面的RequestManager对象
    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);
      // This is a bit of hack, we're going to start the RequestManager, but not the
      // corresponding Lifecycle. It's safe to start the RequestManager, but starting the
      // Lifecycle might trigger memory leaks. See b/154405040
      if (isParentVisible) {
        requestManager.onStart();
      }
      // 设置到SupportRequestManagerFragment里面,下次就不需要创建了
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  
 @NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    // 已经添加过了,可以直接返回  
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      // 从map中获取,取到也可以返回了
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
      // 都没有,那么就创建一个
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        // 将刚创建的fragment缓存起来
        pendingSupportRequestManagerFragments.put(fm, current);
        / 将fragment添加到页面中
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        // 以fm为key从pendingSupportRequestManagerFragments中删除
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }  

从上面的方法可以看出,成功创建了一个RequestManager对象。requestManager对象是由factory.build()方法创建出来。下面就看下factory如何创建的:

private final RequestManagerFactory factory;

public RequestManagerRetriever(
      @Nullable RequestManagerFactory factory, GlideExperiments experiments) {
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);

    frameWaiter = buildFrameWaiter(experiments);
  }

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);
        }
      };

从上文分析getRetriever(Context)可以知道,factory其实就是DEFAULT_FACTORY。到目前为止,Glide.with已经分析完毕。

流程图:
在这里插入图片描述

RequestManager.load

RequestManager.load方法的重载很多,可以传入不同的图片源。

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
  return asDrawable().load(bitmap);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
  return asDrawable().load(drawable);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
  return asDrawable().load(string);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
  return asDrawable().load(uri);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
  return asDrawable().load(file);
}

@SuppressWarnings("deprecation")
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
  return asDrawable().load(resourceId);
}

@SuppressWarnings("deprecation")
@CheckResult
@Override
@Deprecated
public RequestBuilder<Drawable> load(@Nullable URL url) {
  return asDrawable().load(url);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
  return asDrawable().load(model);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Object model) {
  return asDrawable().load(model);
}

从上面的方法中,可以看出load重载方法都会先调用asDrawable()。接下来,看下asDrawable()方法。

 @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
  
  @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }  
 

从上面可以看出,asDrawable()方法调用as()方法,并传入Drawable.class;而as方法创建一个图片类型为Drawable类型的RequestBuilder请求。下面接着看下RequestBuilder:

RequestBuilder.load

RequestManager.load方法都会调用对应的RequestBuilder.load重载方法。

protected RequestBuilder(Glide glide, RequestManager requestManager,
      Class<TranscodeType> transcodeClass, Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    //注意,这里传入的是Drawable.class
    this.transcodeClass = transcodeClass;
    this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.requestOptions = defaultRequestOptions;
    this.glideContext = glide.getGlideContext();
}

public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
}
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    return loadGeneric(uri);
}
public RequestBuilder<TranscodeType> load(@Nullable File file) {
    return loadGeneric(file);
}
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
    return loadGeneric(drawable).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    return loadGeneric(bitmap).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return loadGeneric(resourceId).apply(signatureOf(AndroidResourceSignature.obtain(context)));
}

从上面的代码可以看出,RequestBuilder.load的各个方法基本上都会直接转发给loadGeneric方法,只有少数的方法才会apply额外的options。接着,看下loadGeneric方法:

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    if (isAutoCloneEnabled()) {
      return clone().loadGeneric(model);
    }
    this.model = model;
    isModelSet = true;
    return selfOrThrowIfLocked();
}

protected final T selfOrThrowIfLocked() {
    if (isLocked) {
      throw new IllegalStateException("You cannot modify locked T, consider clone()");
    }
    return self();
}

private T self() {
    return (T) this;
}

该方法主要是将图片源保存起来,并设置是否设置了图片源的标识isModelSet=true,最后返回了RequestBuilder自身this

流程图:
在这里插入图片描述

RequestBuilder.into

通过RequestBuilder.into方法设置目标view

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);
    BaseRequestOptions<?> requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      //熟悉的ScaleType们
      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.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
}

从以上源码来看,into(ImageView)方法的实现,里面会先判断需不需要对图片进行裁切,然后调用别的into重载方法。接下来,重点看最后返回调用into()重载方法,它将view通过buildImageViewTarget方法转为target,transcodeClass为Bitmap.class或Drawable.class。

public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
      
    // imageViewTargetFactory是ImageViewTargetFactory的一个实例  
    
    // transcodeClass在RequestManager.load方法中确定是Drawable.class
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}

public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  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)");
    }
  }
}

这里创建的是DrawableImageViewTarget,然后DrawableImageViewTarget被作为参数传入into方法。

上文中,into() 方法中入参参数Executors.mainThreadExecutor()

public static Executor mainThreadExecutor() {
    return MAIN_THREAD_EXECUTOR;
  }

  private static final Executor MAIN_THREAD_EXECUTOR =
      new Executor() {
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
          handler.post(command);
        }
      };

Executors.mainThreadExecutor()就是一个使用MainLooper的Handler,在execute Runnable时使用此Handler post出去。

现在,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()");
    }
    //重点1:创建了一个SingleRequest类型 request 对象
    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;
    }
    //将target原先所关联的请求断开
    requestManager.clear(target);
    //并设置为新的请求,
    target.setRequest(request);
    // 然后通过requestManager.track()进行一些列的加载和处理显示操作
    // 重点2:真正开始网络图片的加载
    requestManager.track(target, request);

    return target;
}

重点1:buildRequest

跟踪一下buildRequest的流程,看看是如何创建出SingleRequest的

private Request buildRequest(
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> requestOptions,
    Executor callbackExecutor) {
  return buildRequestRecursive(
      target,
      targetListener,                       // null
      /*parentCoordinator=*/ null,
      transitionOptions,
      requestOptions.getPriority(),         // Priority.NORMAL
      requestOptions.getOverrideWidth(),    // UNSET
      requestOptions.getOverrideHeight(),   // UNSET
      requestOptions,
      callbackExecutor);                    // Executors.mainThreadExecutor()
}

private Request buildRequestRecursive(
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    @Nullable RequestCoordinator parentCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    BaseRequestOptions<?> requestOptions,
    Executor callbackExecutor) {
        
    ....
    
    // 如何获得SingleRequest
  Request mainRequest =
      buildThumbnailRequestRecursive(
          target,
          targetListener,       // null
          parentCoordinator,    // null
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          requestOptions,
          callbackExecutor);
    ...          
        
}

private Request buildThumbnailRequestRecursive(
    Target<TranscodeType> target,
    RequestListener<TranscodeType> targetListener,
    @Nullable RequestCoordinator parentCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    BaseRequestOptions<?> requestOptions,
    Executor callbackExecutor) {
  // thumbnail重载方法没有调用过,所以会走最后的else case
  if (thumbnailBuilder != null) {
    ...
  } else if (thumbSizeMultiplier != null) {
    ...
  } else {
    // Base case: no thumbnail.
    return obtainRequest(
        target,
        targetListener,
        requestOptions,
        parentCoordinator,
        transitionOptions,
        priority,
        overrideWidth,
        overrideHeight,
        callbackExecutor);
  }
}

private Request obtainRequest(
    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,
      model,
      transcodeClass,
      requestOptions,
      overrideWidth,
      overrideHeight,
      priority,
      target,
      targetListener,
      requestListeners,
      requestCoordinator,
      glideContext.getEngine(),
      transitionOptions.getTransitionFactory(),
      callbackExecutor);
}

上面代码中,中间好多是处理缩略图的逻辑,最后会到obtainRequest()方法中。 SingleRequest 类通过静态obtain() 方法返回Request。

重点2:RequestManager.track

// RequestManager

@GuardedBy("this")
private final TargetTracker targetTracker = new TargetTracker();
  
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    // 将target保存到了内部的targets中
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

targetTracker在声明的时候直接初始化,该类的作用是保存所有的Target并向它们转发生命周期事件;requestTracker在RequestManager的构造器中传入了new RequestTracker(),该类的作用管理所有状态的请求。

//RequestTracker.java

public void runRequest(@NonNull Request request) {
    // requests 正在请求集合
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      // pendingRequests 等待请求集合
      pendingRequests.add(request);
    }
  }

isPaused默认为false,会执行request.begin()方法。上面说到过,这里的request实际上是SingleRequest对象,我们看一下它的begin()方法。

// SingleRequest

public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      // 如果model为空,会调用监听器的onLoadFailed处理
      // 若无法处理,则展示失败时的占位图
    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");
      }
      
      // 如果我们在请求完成后想重新开始加载,那么就会返回已经加载好的资源
      // 如果由于view尺寸的改变,我们的确需要重新来加载,此时我们需要明确地清除View或Target
      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }
      
      
      // 如果指定了overrideWidth和overrideHeight,那么直接调用onSizeReady方法,否则会获取ImageView的宽、高
      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        //将目标view的宽高传入onSizeReady
        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));
      }
    }
}

接下来会获取要加载图片的size并调用onSizeReady方法,我们直接看该方法:

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      ...
      if (status != Status.WAITING_FOR_SIZE) {
        return;
      }
      //修改status为running
      status = Status.RUNNING;
      // 将原始尺寸与0~1之间的系数相乘,取最接近的整数值,得到新的尺寸
      float sizeMultiplier = requestOptions.getSizeMultiplier();
      this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
      this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

      //调用Engine.load对请求进行处理
      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);
      // status目前显然是RUNNING状态,所以不会将loadStatus设置为null
      if (status != Status.RUNNING) {
        loadStatus = null;
      }
    }
}

Engine.load

engine.load 是开始请求的关键代码了,Engine是负责开始加载,管理active、cached状态资源的类。

// Engine

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) {
      // 获取缓存中的图片资源
      // 分析1
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        // 缓存中没有则等待或新开一个job获取图片资源
        // 分析2
        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, /* isLoadedFromAlternateCacheKey= */ false);
    return null;
  }

上面的方法,主要是先通过loadFromMemory获取缓存中的图片资源,取不到则调用waitForExistingOrStartNewJob。

分析1:Engine.loadFromMemory
@Nullable
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
      //判断是否允许内存缓存
    if (!isMemoryCacheable) {
      return null;
    }
      //从活动缓存中取
    EngineResource<?> active = loadFromActiveResources(key);
    if (active != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return active;
    }
      //从内存缓存中取
    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return cached;
    }

    return null;
  }

该方法中,首先从ActiveResources中取资源,如果获取不到,就从内存缓存中取资源。活动缓存和内存缓存属于运行时缓存

接下来,查看loadFromActiveResources()方法:

// Engine

  private final ActiveResources activeResources;
 
  @Nullable
  private EngineResource<?> loadFromActiveResources(Key key) {
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }

    return active;
  }
  
// ActiveResources

final class ActiveResources {
    final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
    ....
    
    @Nullable
  synchronized EngineResource<?> get(Key key) {
    ResourceWeakReference activeRef = activeEngineResources.get(key);
    if (activeRef == null) {
      return null;
    }

    EngineResource<?> active = activeRef.get();
    if (active == null) {
      cleanupActiveReference(activeRef);
    }
    return active;
  }
  
  
  ....
}

// EngineResource<Z> 

class EngineResource<Z> implements Resource<Z> {
    ...
    private int acquired;
    private boolean isRecycled;
    ...
    synchronized void acquire() {
        if (isRecycled) {
          throw new IllegalStateException("Cannot acquire a recycled resource");
        }
        ++acquired;
    }
}

从上面源码来看,ActiveResources维护了一个value为弱引用HashMap<Key,ResourceWeakReference>, 调用其get方法获取图片资源,如果取到则调用acquire对 对象的引用数量 进行加一操作,内存缓存是通过计数散列算法来进行相应的操作的,如果对象的计数树为0,则说明暂无其他对象引用此资源,那么此资源可以被释放了。

分析2:Engine.waitForExistingOrStartNewJob

loadFromMemory()方法取不到,则调用waitForExistingOrStartNewJob()去获取图片资源。

final class Jobs {
  private final Map<Key, EngineJob<?>> jobs = new HashMap<>();
  private final Map<Key, EngineJob<?>> onlyCacheJobs = new HashMap<>();
  ...
}
private <R> LoadStatus waitForExistingOrStartNewJob(...) {
    //先从jobs中取EngineJob
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    // 检测有没有真正执行的缓存可用(磁盘缓存)
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      //取到则直接创建一个LoadStatus返回
      return new LoadStatus(cb, current);
    }

    //取不到则通过engineJobFactory.build创建一个EngineJob
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
    // 构建出一个DecodeJob,该类实现了Runnable接口
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    //将创建的engineJob加入到jobs
    jobs.put(key, engineJob);
   //注册ResourceCallback
    engineJob.addCallback(cb, callbackExecutor);
    //调用start开启线程获取图片
    // 执行decodeJob任务
    engineJob.start(decodeJob);

    return new LoadStatus(cb, engineJob);
}

在上面的方法中,最重要是engineJob.start() 开启线程获取图片,源码如下:

// EngineJob

public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    // willDecodeFromCache() 为true
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    //  executor 为diskCacheExecutor   
    executor.execute(decodeJob);
}

boolean willDecodeFromCache() {
    // firstStage返回值为Stage.RESOURCE_CACHE
    Stage firstStage = getNextStage(Stage.INITIALIZE);
    return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}

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);
    }
  }  

从上面的start()方法中,GlideExecutor类型的executor值为diskCacheExecutor,它的初始化操作是放在GlideBuilder.build()方法里。

// GlideBuilder 

diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();

public final class GlideExecutor implements ExecutorService {
    public static GlideExecutor newDiskCacheExecutor() {
        return newDiskCacheBuilder().build();
    }
    public static GlideExecutor.Builder newDiskCacheBuilder() {
        return new GlideExecutor.Builder(/*preventNetworkOperations=*/ true)
            .setThreadCount(DEFAULT_DISK_CACHE_EXECUTOR_THREADS)
            .setName(DEFAULT_DISK_CACHE_EXECUTOR_NAME);
    }
    GlideExecutor(ExecutorService delegate) {
        this.delegate = delegate;
    }
    public void execute(@NonNull Runnable command) {
        delegate.execute(command);
    }
    public static final class Builder {
        ...
        public GlideExecutor build() {
              if (TextUtils.isEmpty(name)) {
                throw new IllegalArgumentException(
                    "Name must be non-null and non-empty, but given: " + name);
              }
              ThreadPoolExecutor executor =
                  new ThreadPoolExecutor(
                      corePoolSize,
                      maximumPoolSize,
                      /*keepAliveTime=*/ threadTimeoutMillis,
                      TimeUnit.MILLISECONDS,
                      new PriorityBlockingQueue<Runnable>(),
                      new DefaultThreadFactory(name, uncaughtThrowableStrategy, preventNetworkOperations));

              if (threadTimeoutMillis != NO_THREAD_TIMEOUT) {
                executor.allowCoreThreadTimeOut(true);
              }

              return new GlideExecutor(executor);
          }
    }
}

从上面源码来看,GlideExecutor其实就是个线程池。并且,DecodeJob是实现Runnable接口的类,放到线程池中去执行。不管是磁盘缓存还是内存缓存最终都会调用DecodeJob,接下来看DecodeJob 类重点run() 方法。

DecodeJob.run

DecodeJob 的run()方法里面重点关注runWrapped()操作。

private enum Stage {
    /** The initial stage. */
    INITIALIZE,
    /** Decode from a cached resource. */
    RESOURCE_CACHE,
    /** Decode from cached source data. */
    DATA_CACHE,
    /** Decode from retrieved source. */
    SOURCE,
    /** Encoding transformed resources after a successful load. */
    ENCODE,
    /** No more viable stages. */
    FINISHED,
}

class DecodeJob<R>
    implements DataFetcherGenerator.FetcherReadyCallback,
        Runnable, Comparable<DecodeJob<?>>, Poolable {
    
    private volatile DataFetcherGenerator currentGenerator;        
    
    public void run() {
        ...
        try {
          if (isCancelled) {
            notifyFailed();
            return;
          }

          runWrapped();
        } catch (
        ...
    }

    private void runWrapped() {
    //runReason在DecodeJob初始化的时候初始值是INITIALIZE
        switch (runReason) {
          
          case INITIALIZE:// 首次提交任务
            //调用getNextStage后返回Stage.RESOURCE_CACHE
            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:
       // ResourceCacheGenerator:获取采样后、transformed后资源文件的缓存文件
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
       // DataCacheGenerator:获取原始的没有修改过的资源文件的缓存文件
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
      // SourceGenerator:获取原始源数据
        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())) {
      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();
    }
}
            
}

getNextGenerator()方法的RESOURCE_CACHE和DATA_CACHE这2种策略必须使用Glide加载图片设置缓存策略,才会调用这2种;否则直接会调用SOURCE情况,请求图片资源。

上面的runGenerators()方法会依次调用各个状态生成的ResourceCacheGenerator、DataCacheGenerator、SourceGenerator的startNext()尝试fetch数据,直到有某个状态的DataFetcherGenerator.startNext()方法可以胜任。若状态抵达到了Stage.FINISHED或job被取消,且所有状态的DataFetcherGenerator.startNext()都无法满足条件,则调用SingleRequest.onLoadFailed进行错误处理。

ResourceCacheGenerator

接着,继续看ResourceCacheGenerator.startNext()方法。

// ResourceCacheGenerator

private final DecodeHelper<?> helper;

@Override
  public boolean startNext() {
    // list里面只有一个GlideUrl对象 
    List<Key> sourceIds = helper.getCacheKeys();
    if (sourceIds.isEmpty()) {
      return false;
    }
    // list集合返回类型为:GifDrawable、Bitmap、BitmapDrawable
    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);
      
       currentKey =
          new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
              helper.getArrayPool(),
              sourceId,
              helper.getSignature(),
              helper.getWidth(),
              helper.getHeight(),
              transformation,
              resourceClass,
              helper.getOptions());
      cacheFile = helper.getDiskCache().get(currentKey);
      if (cacheFile != null) {
        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())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }

    return started;
  }
  

SourceGenerator

由于第一次加载,本地缓存文件肯定是没有的。看下SourceGenerator,看它是如何获取数据的。

private int loadDataListIndex;

@Override
public boolean startNext() {
  // 首次运行dataToCache为null
  if (dataToCache != null) {
    Object data = dataToCache;
    dataToCache = null;
    cacheData(data);
  }

  // 首次运行sourceCacheGenerator为null
  if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
    return true;
  }
  sourceCacheGenerator = null;

  // 准备加载数据
  loadData = null;
  boolean started = false;
  
  while (!started && hasNextModelLoader()) {
    // 遍历LoadData list
    loadData = helper.getLoadData().get(loadDataListIndex++);
    // 找出符合条件的LoadData
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
        || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
      started = true;
      startNextLoad(loadData);
    }
  }
  return started;
}

private boolean hasNextModelLoader() {
  return loadDataListIndex < helper.getLoadData().size();
}

private void startNextLoad(final LoadData<?> toStart) {
    // fetcher是HttpUrlFetcher
    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);
            }
          }
        });
  }

startNextLoad()方法根据HttpUrlFetcher去加载数据。为啥是HttpUrlFetcher?看如下代码:

// DecodeHelper 

List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      // 
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //noinspection ForLoopReplaceableByForEach to improve perf
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }


// HttpGlideUrlLoader

public LoadData<InputStream> buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
  

接着,继续分析HttpUrlFetcher的loadData()方法。

//HttpUrlFetcher.java

public void loadData(@NonNull Priority priority,
      @NonNull DataCallback<? super InputStream> callback) {
    try {
      //请求网络
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      //将数据返回回去
      callback.onDataReady(result);
    } catch (IOException e) {
      callback.onLoadFailed(e);
    } finally {
    }
}

 private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
    ...

    urlConnection = buildAndConfigureConnection(url, headers);

    try {
      // Connect explicitly to avoid errors in decoders if connection fails.
      urlConnection.connect();
      // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
      stream = urlConnection.getInputStream();
    } catch (IOException e) {
      throw new HttpException(
          "Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
    }

    if (isCancelled) {
      return null;
    }

    final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
    ...
}

// 网络请求相关的代码
private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
      throws HttpException {
    HttpURLConnection urlConnection;
    try {
      urlConnection = connectionFactory.build(url);
    } catch (IOException e) {
      throw new HttpException("URL.openConnection threw", /*statusCode=*/ 0, e);
    }
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);
    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);
    return urlConnection;
}

通过HttpURLConnection进行的网络请求,并且结果就是通过urlConnection.getInputStream();这里拿到了结果后,就返回了,然后就是上面的callback.onDataReady(result);进行回调处理结果。

SourceGenerator.onDataReadyInternal

从上面SourceGenerator.startNextNext中的loadData.fetcher.loadData的入参DataCallback的onDataReady我们知道,如果请求成功,会将资源通过onDataReady传递回去,其中调用了onDataReadyInternal,代码如下:

void onDataReadyInternal(LoadData<?> loadData, 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.reschedule();
    } else {
      //cb为DecodeJob
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
}

看一下DecodeJob.onDataFetcherReady

// 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;
    this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);

    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        // 解码图片资源
        decodeFromRetrievedData();
      } finally {
        GlideTrace.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 {
       // 分析1
      // 从数据中解码得到资源
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      // 分析2
      notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
    } else {
      runGenerators();
    }
}

decodeFromRetrievedData()方法会先调用decodeFromData方法进行解码,然后调用notifyEncodeAndRelease方法进行缓存。

分析1:decodeFromData调用流程
private <Data> Resource<R> decodeFromData(
      DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }

  @SuppressWarnings("unchecked")
  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    //将解码交给LoadPath对象
    return runLoadPath(data, dataSource, path);
  }
  
  private <Data, ResourceType> Resource<R> runLoadPath(
      Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
      throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      // ResourceType in DecodeCallback below is required for compilation to work with gradle.
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }

从decodeFromData()方法可以看出,该方法内部又调用decodeFromFetcher()方法;在decodeFromFetcher()方法中会获取LoadPath,然后调用runLoadPath()方法解析成资源。

在runLoadPath()方法中会调用path.load()方法,下面看下相关代码:

// LoadPath

 public Resource<Transcode> load(
      DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback<ResourceType> decodeCallback)
      throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }
  
 private Resource<Transcode> loadWithExceptionList(
      DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions)
      throws GlideException {
    Resource<Transcode> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
         // 重点
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }

    return result;
  }

在loadWithExceptionList()方法中,对于每条DecodePath,都调用其decode方法,直到有一个DecodePath可以decode出资源。继续看看DecodePath.decode()方法:

// DecodePath

public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
    @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    
  Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
  
  Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
  
  return transcoder.transcode(transformed, options);
}

@NonNull
  private Resource<ResourceType> decodeResource(
      DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options)
      throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

  @NonNull
  private Resource<ResourceType> decodeResourceWithList(
      DataRewinder<DataType> rewinder,
      int width,
      int height,
      @NonNull Options options,
      List<Throwable> exceptions)
      throws GlideException {
    Resource<ResourceType> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          //根据DataType, ResourceType区别,分发给不同的解码器
          result = decoder.decode(data, width, height, options);
        }
        // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but
        // instead log and continue. See #2406 for an example.
      } catch (IOException | RuntimeException | OutOfMemoryError e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          Log.v(TAG, "Failed to decode data for " + decoder, e);
        }
        exceptions.add(e);
      }

      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }

上面的decoder其实是StreamBitmapDecoder,在初始化Glide的时候就初始化好了。

// StreamBitmapDecoder

public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
      @NonNull Options options)
      throws IOException {
    ...
    //这里又将解码任务交给了Downsampler
    return downsampler.decode(invalidatingStream, width, height, options, callbacks);
}

上面的方法会将decode出来的Bitmap包装成为一个BitmapResource对象。然后就一直往上返回,返回到DecodePath.decode方法中。 继续执行如下代码:

// DecodePath
 Resource<ResourceType> transformed=callback.onResourceDecoded(decoded);
 
// DecodeJob
  @Synthetic
  @NonNull
  <Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    // TODO: Make this the responsibility of the Transformation.
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }

    final EncodeStrategy encodeStrategy;
    final ResourceEncoder<Z> encoder;
    if (decodeHelper.isResourceEncoderAvailable(transformed)) {
      encoder = decodeHelper.getResultEncoder(transformed);
      encodeStrategy = encoder.getEncodeStrategy(options);
    } else {
      encoder = null;
      encodeStrategy = EncodeStrategy.NONE;
    }

    Resource<Z> result = transformed;
    boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
    if (diskCacheStrategy.isResourceCacheable(
        isFromAlternateCacheKey, dataSource, encodeStrategy)) {
      if (encoder == null) {
        throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
      }
      final Key key;
      switch (encodeStrategy) {
        case SOURCE:
          key = new DataCacheKey(currentSourceKey, signature);
          break;
        case TRANSFORMED:
          key =
              new ResourceCacheKey(
                  decodeHelper.getArrayPool(),
                  currentSourceKey,
                  signature,
                  width,
                  height,
                  appliedTransformation,
                  resourceSubClass,
                  options);
          break;
        default:
          throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
      }

      LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
      deferredEncodeManager.init(key, encoder, lockedResult);
      result = lockedResult;
    }
    return result;
  }

这里会调用DecodeJob.onResourceDecoded(DataSource,Resource)方法。至此,resource已经decode完毕。

分析2:notifyEncodeAndRelease调用流程

返回到DecodeJob.decodeFromRetrievedData()方法中,会调用notifyEncodeAndRelease方法。下面看看其代码:

private void notifyEncodeAndRelease(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
      // resource是BitmapResource类型,实现了Initializable接口
    if (resource instanceof Initializable) {
    // initialize方法调用了bitmap.prepareToDraw()
      ((Initializable) resource).initialize();
    }

    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }
   // 通知回调,资源已经就绪
    notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);

    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
    // 进行清理工作
    onEncodeComplete();
  }
  
  private void notifyComplete(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
  }

上面这段代码重点在于notifyComplete方法,该方法内部会调用callback.onResourceReady(resource, dataSource)将结果传递给回调,这里的回调是EngineJob。

// EngineJob
final ResourceCallbacksAndExecutors cbs = new ResourceCallbacksAndExecutors();

@Override
  public void onResourceReady(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
      this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
    }
    notifyCallbacksOfResult();
  }
  
  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
        // TODO: Seems like we might as well put this in the memory cache instead of just recycling
        // it since we've gotten this far...
        resource.recycle();
        release();
        return;
      } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
      } else if (hasResource) {
        throw new IllegalStateException("Already have resource");
      }
      // engineResourceFactory默认为EngineResourceFactory,其build方法就是new一个对应的资源
      engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
      ...
      
      copy = cbs.copy();
      incrementPendingCallbacks(copy.size() + 1);

      localKey = key;
      localResource = engineResource;
    }
    // listener就是Engine,该方法将资源保存到activeResources中
    engineJobListener.onEngineJobComplete(this, localKey, localResource);
    
    // entry.executor就是Glide.with.load.into中出现的Executors.mainThreadExecutor()
    // entry.cb就是SingleRequest
    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
  
// Engine
  public synchronized void onEngineJobComplete(
      EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null && resource.isMemoryCacheable()) {
      activeResources.activate(key, resource);
    }

    jobs.removeIfCurrent(key, engineJob);
  }

继续看 engineJobListener.onEngineJobComplete()这行代码,设置资源的回调,将资源放入activeResources中,资源变为active状态,最后将engineJob从Jobs中移除。

接下来,注重看下 CallResourceReady类

// EngineJob

private class CallResourceReady implements Runnable {

    private final ResourceCallback cb;

    CallResourceReady(ResourceCallback cb) {
      this.cb = cb;
    }

    @Override
    public void run() {
      // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
      // (b/136032534).
      synchronized (cb.getLock()) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            callCallbackOnResourceReady(cb);
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }
  }
  
   void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      // This is overly broad, some Glide code is actually called here, but it's much
      // simpler to encapsulate here than to do so at the actual call point in the
      // Request implementation.
      cb.onResourceReady(engineResource, dataSource, isLoadedFromAlternateCacheKey);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

上面代码中run()方法,首先用callCallbackOnResourceReady(cb)调用callback,然后调用removeCallback(cb)移除callback。callCallbackOnResourceReady()方法中调用cb.onResourceReady();其实cb就是SingleRequest。接着看SingleRequest.onResourceReady方法。

// SingleRequest

 @Override
  public void onResourceReady(
      Resource<?> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    stateVerifier.throwIfRecycled();
    Resource<?> toRelease = null;
    try {
      synchronized (requestLock) {
        loadStatus = null;
        if (resource == null) {
          GlideException exception =
              new GlideException(
                  "Expected to receive a Resource<R> with an "
                      + "object of "
                      + transcodeClass
                      + " inside, but instead got null.");
          onLoadFailed(exception);
          return;
        }

        Object received = resource.get();
        if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
          toRelease = resource;
          this.resource = null;
          GlideException exception =
              new GlideException(
                  "Expected to receive an object of "
                      + transcodeClass
                      + " but instead"
                      + " got "
                      + (received != null ? received.getClass() : "")
                      + "{"
                      + received
                      + "} inside"
                      + " "
                      + "Resource{"
                      + resource
                      + "}."
                      + (received != null
                          ? ""
                          : " "
                              + "To indicate failure return a null Resource "
                              + "object, rather than a Resource object containing null data."));
          onLoadFailed(exception);
          return;
        }

        if (!canSetResource()) {
          toRelease = resource;
          this.resource = null;
          // We can't put the status to complete before asking canSetResource().
          status = Status.COMPLETE;
          return;
        }
        // 重点方法
        onResourceReady(
            (Resource<R>) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey);
      }
    } finally {
      if (toRelease != null) {
        engine.release(toRelease);
      }
    }
  }
  
  private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
  // We must call isFirstReadyResource before setting status.
  // 由于requestCoordinator为null,所以返回true
  boolean isFirstResource = isFirstReadyResource();
  // 将status状态设置为COMPLETE
  status = Status.COMPLETE;
  this.resource = resource;

  if (glideContext.getLogLevel() <= Log.DEBUG) {
    Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
        + dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
        + LogTime.getElapsedMillis(startTime) + " ms");
  }

  isCallingCallbacks = true;
  try {
     // 尝试调用各个listener的onResourceReady回调进行处理
    boolean anyListenerHandledUpdatingTarget = false;
    if (requestListeners != null) {
      for (RequestListener<R> listener : requestListeners) {
        anyListenerHandledUpdatingTarget |=
            listener.onResourceReady(result, model, target, dataSource, isFirstResource);
      }
    }
    anyListenerHandledUpdatingTarget |=
        targetListener != null
            && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

    // 如果没有一个回调能够处理,那么自己处理
    if (!anyListenerHandledUpdatingTarget) {
      // animationFactory默认为NoTransition.getFactory(),生成的animation为NO_ANIMATION
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
          
      // target为DrawableImageViewTarget
      target.onResourceReady(result, animation);
    }
  } finally {
    isCallingCallbacks = false;
  }

  // 通知requestCoordinator
  notifyLoadSuccess();
}

DrawableImageViewTarget的基类ImageViewTarget实现了此方法:

// ImageViewTarget.java
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
  // NO_ANIMATION.transition返回false,所以直接调用setResourceInternal方法
  if (transition == null || !transition.transition(resource, this)) {
    setResourceInternal(resource);
  } else {
    maybeUpdateAnimatable(resource);
  }
}

private void setResourceInternal(@Nullable Z resource) {
  // Order matters here. Set the resource first to make sure that the Drawable has a valid and
  // non-null Callback before starting it.
  // 先设置图片
  setResource(resource);
  // 然后如果是动画,会执行动画
  maybeUpdateAnimatable(resource);
}

private void maybeUpdateAnimatable(@Nullable Z resource) {
  // BitmapDrawable显然不是一个Animatable对象,所以走else分支
  if (resource instanceof Animatable) {
    animatable = (Animatable) resource;
    animatable.start();
  } else {
    animatable = null;
  }
}

// DrawableImageViewTarget
@Override
protected void setResource(@Nullable Drawable resource) {
  view.setImageDrawable(resource);
}

至此网络图片已经通过view.setImageDrawable(resource)加载完毕。

into 流程图:
在这里插入图片描述

Glide 整体流程

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值