GlideApp源码分析

 先放上glide地址:

https://github.com/bumptech/glide

glide发展到今日已经到了4.9.0,具体的用法在之前也有讲过了,具体请看:

 Glide基础用法(一)

 Glide基础用法(二)

 这篇文章主要从源码方面解读Glide。

 1:AppGlideModule和GlideModule

   我们都知道想要使用glideApp需要先创建一个文件继承AppglideModule并实现GlideModule注解。如:

@GlideModule
public final class GlobalGlideConfig extends AppGlideModule {

}

   那AppGlideModule和GlideModule注解具体实现了什么呢?

   我们先看下AppGlideModule的代码:

public abstract class AppGlideModule extends LibraryGlideModule implements AppliesOptions {
  /**
   * Returns {@code true} if Glide should check the AndroidManifest for {@link GlideModule}s.
   *
   * <p>Implementations should return {@code false} after they and their dependencies have migrated
   * to Glide's annotation processor.
   *
   * <p>Returns {@code true} by default.
   */
  public boolean isManifestParsingEnabled() {
    return true;
  }

  @Override
  public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
    // Default empty impl.
  }
}



public abstract class LibraryGlideModule implements RegistersComponents {
  @Override
  public void registerComponents(@NonNull Context context, @NonNull Glide glide,
      @NonNull Registry registry) {
    // Default empty impl.
  }
}



 

isManifestParsingEnabled默认返回true;用途是否检测manifest里面的GlideModule。

上面的源码中也告诉我们当继承AppGlideModule时,最好实现这个方法,并默认返回false。这样避免AndroidManifest加载两次。

applyOptions()主要用来对GlideBuilder进行设置。

registerComponents()注册在应用程序中初始化Glide时要使用的一组组件.

//在编译时,为AppGlideModules和LibraryGlideModules提供注入。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface GlideModule {
  /**
   * Returns the name of the class that will be used as a replacement for
   * {@code com.bumptech.glide.Glide} in Applications that depend on Glide's generated code.
   */
  String glideName() default "GlideApp";
}

  我们可以看到注解GlideModule中默认了GlideName为GlideApp.调用的时候就是GlideApp.with(this);

2:with()

  查看源码我们可以知道GlideApp的多个with方法其实实现的还是Glide.with(),并返回GlideRequests。

  /**
   * @see Glide#with(Context)
   */
  @NonNull
  public static GlideRequests with(@NonNull Context context) {
    return (GlideRequests) Glide.with(context);
  }

  /**
   * @see Glide#with(Activity)
   */
  @NonNull
  public static GlideRequests with(@NonNull Activity activity) {
    return (GlideRequests) Glide.with(activity);
  }

  /**
   * @see Glide#with(FragmentActivity)
   */
  @NonNull
  public static GlideRequests with(@NonNull FragmentActivity activity) {
    return (GlideRequests) Glide.with(activity);
  }

  /**
   * @see Glide#with(Fragment)
   */
  @NonNull
  public static GlideRequests with(@NonNull Fragment fragment) {
    return (GlideRequests) Glide.with(fragment);
  }

  /**
   * @see Glide#with(Fragment)
   */
  @Deprecated
  @NonNull
  public static GlideRequests with(@NonNull android.app.Fragment fragment) {
    return (GlideRequests) Glide.with(fragment);
  }

  /**
   * @see Glide#with(View)
   */
  @NonNull
  public static GlideRequests with(@NonNull View view) {
    return (GlideRequests) Glide.with(view);
  }

 我们以Glide.with(Activity)为例:

  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  } 

/**
   * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
   * and that uses the given {@link Activity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given activity that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

可以看到with()方法就是调用getRequestManagerRetriever().get()来获取一个RequestManagerRetriever对象。

传入参数activity是为了绑定activity,当Activity 销毁的时候Glide会停止图片的加载。

至于RequestManagerRetriever中具体通过单例模式返回RequestManager 对象,

@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) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

 @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
          "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
     //判断当前activity是否被销毁
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

从get(Context context)中我们可以看到根据context instance application来判断,当传入对象是application时调用getApplicationManager()返回RequestManager;

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

当传入不是application时又分为两种:

第一种supportFragmentGet

  @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    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);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

第二种fragmentGet

 @SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
  @Deprecated
  @NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    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);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

两种方法基本一致,都是创建一个没有界面的的fragment并add到当前activity中,以此来实现对activity生命周期的监听。

 @SuppressWarnings("deprecation")
  @NonNull
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

3:GlideBuilder

   用于设置Glide要使用的默认结构类的构建器类.

  具体的set方法等可查看api:

  https://bumptech.github.io/glide/javadocs/410/com/bumptech/glide/GlideBuilder.html

 

  @NonNull
  Glide build(@NonNull Context context) {
    //创建图片线程池
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    // 创建硬盘缓存线程池diskCacheExecutor
    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    // 创建动画线程池animationExecutor
    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) {
     // 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap
        bitmapPool = new LruBitmapPool(size);
      } else {

        bitmapPool = new BitmapPoolAdapter();
      }
    }
    // 创建对象数组缓存池LruArrayPool,默认4M

    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(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  }

 4:load(url)

  

  我们可以看到load是GlideRequest的方法,

  


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

 如上是加载的super.load();我们看到GlideRequest是继承自GlideManager,所以继续查看GlideManager的load方法。

@NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Bitmap)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
    return asDrawable().load(bitmap);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Drawable)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
    return asDrawable().load(drawable);
  }

  /**
   * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }

继续点进去可以看到

  /**
   * Returns a request builder to load the given {@link java.lang.String}.
   *
   * <p> Note - this method caches data using only the given String as the cache key. If the data is
   * a Uri outside of your control, or you otherwise expect the data represented by the given String
   * to change without the String identifier changing, Consider using
   * {@link com.bumptech.glide.request.RequestOptions#signature(com.bumptech.glide.load.Key)} to
   * mixin a signature you create that identifies the data currently at the given String that will
   * invalidate the cache if that data changes. Alternatively, using
   * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
   * {@link com.bumptech.glide.request.RequestOptions#skipMemoryCache(boolean)} may be
   * appropriate.
   * </p>
   *
   * @see #load(Object)
   *
   * @param string A file path, or a uri or url handled by
   * {@link com.bumptech.glide.load.model.UriLoader}.
   */
  @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }

 //设置model

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

5:into

如上所示:into 主要有三种传参方式:

5.1Imageview

 

  /**
   * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into
   * the view, and frees any resources Glide may have previously loaded into the view so they may be
   * reused.
   *
   * @see RequestManager#clear(Target)
   *
   * @param view The view to cancel previous loads for and load the new resource into.
   * @return The
   * {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
   */
  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    //判断是否是在主线程
    Util.assertMainThread();
    //判空
    Preconditions.checkNotNull(view);

    //ScaleType配置
    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }


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

 

glideContext是在Glide构造方法中创建的
into(ImageView)实际返回的还是into(target)的三个参数的方法。另外 glideContext.buildImageViewTarget(view, transcodeClass)获取到target对象传入参数。

 

 /**
   * Set the target the resource will be loaded into.
   *
   * @param target The target to load the resource into.
   * @return The given target.
   * @see RequestManager#clear(Target)
   */
  @NonNull
  public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    return into(target, /*targetListener=*/ null);
  }

  @NonNull
  @Synthetic <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener) {
    return into(target, targetListener, getMutableOptions());
  }

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);

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

    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

  首先Util.assertMainThread()判断是否在主线程,Preconditions.checkNotNull(target)判断是否为空。

 在上一步我们可以看到isModelSet是在loadGeneric方法中设置为true的,所以ismodelset也就是判断是否调用了load方法。

 target.getRequest() 获取当前Request对象。

 request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)判断两个请求是否相同,并且当前绑定的request 即previous是否调用skipMemoryCache。

begin()  -->启动异步加载

track()方法:

 void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值