IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Glide setDefaultRequestOptions 源码分析 -> 正文阅读

[移动开发]Glide setDefaultRequestOptions 源码分析

Glide源码分析

一、现状

以下为一次Glide图片加载典型用法,会将所需相关配置写入 requestOptions 对象,通过 setDefaultRequestOptions 方法写入自定义配置。

                RequestOptions requestOptions =
                        RequestOptions.skipMemoryCacheOf(true).diskCacheStrategy(DiskCacheStrategy.NONE).dontAnimate()
                                .dontTransform();
                if (circleImg) {
                    requestOptions = requestOptions.transform(new CircleCrop());
                }
                if (placeHolder > 0) {
                    requestOptions = requestOptions.placeholder(placeHolder);
                }
                if (errorHolder > 0) {
                    requestOptions = requestOptions.error(errorHolder);
                }
                if (roundRadius > 0f) {
                    requestOptions = requestOptions.transform(new CenterCrop(),
                            new RoundedCorners(ScreenUtil.dp2px(context, roundRadius)));
                }

								Glide.with(context)
                            .setDefaultRequestOptions(requestOptions)
                            .load(uri)
                            .addListener(new RequestListener<Drawable>() {})
                            .into(imageView);

二、存在问题

当使用Glide进行图片加载时,若没有调用过 setDefaultRequestOptions 进行配置,可能存在将其他地方配置加载过来的情况,造成错乱。

三、原因分析

根据方法定义,初步判定是由于 setDefaultRequestOptions 存在持久化问题,在设置过一次后将会在后续操作中持续 生效,直至下一次重新调用。

四、源码分析

4.1 Glide.with(context)

初始化入口方法,返回值 RequestManager

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

Glide#getRetriever 返回值 RequestManagerRetriever

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

Glide.get 单例方法 返回值 Glide

@NonNull
public static Glide get(@NonNull Context context) {
  if (glide == null) {
    synchronized (Glide.class) {
      if (glide == null) {
        checkAndInitializeGlide(context);
      }
    }
  }

  return glide;
}

小结

Glide (singleInstance) -> RequestManagerRetriever -> RequestManager

4.2 Glide 初始化

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

  private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext();

    // ..........此处省略部分代码............
    
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
    builder.setRequestManagerFactory(factory);
 
    // ..........此处省略部分代码............
    
    Glide glide = builder.build(applicationContext);

    // ..........此处省略部分代码............

    Glide.glide = glide;
  }

4.3 GlideBuilder 初始化

public final class GlideBuilder {
  
  private RequestOptions defaultRequestOptions = new RequestOptions();

  @NonNull
  public GlideBuilder setDefaultRequestOptions(@Nullable RequestOptions requestOptions) {
    this.defaultRequestOptions = requestOptions;
    return this;
  }
  
  Glide build(@NonNull Context context) {

  	// ..........此处省略部分代码............
  
    // 此处 RequestManagerRetriever 初始化
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        // 此处 requestManagerRetriever 赋值
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        // 此处 defaultRequestOptions 赋值
        defaultRequestOptions.lock(),
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled);
	}
}

小结

Glide 通过 GlideBuilder 进行初始化,并且在初始化时会为 RequestOptions 进行赋值,而赋值的 RequestOptions 对象在 GlideBuilder中通过无参构造被初始化,可判定该对象为初始默认配置

RequestManagerRetriever 通过 GlideBuilder 进行初始化,并且赋值给Glide。

4.4 RequestManagerRetriever

Glide.get(context).getRequestManagerRetriever()

public class Glide implements ComponentCallbacks2 {
  private final RequestManagerRetriever requestManagerRetriever;
  
  /**
   * Internal method.
   */
  @NonNull
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }
}

4.5 RequestManager

RequestManagerRetriever#get(Context)

@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)) {
    // 通过Activity添加Fragment 获取lifecycler 并且初始化 RequestManager
    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());
    }
  }
	
  // 初始化不含 lifecycler 的 RequestManager 单例
  return getApplicationManager(context);
}

@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  // 后台线程使用applicationContext
  if (Util.isOnBackgroundThread()) {
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(
        activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(@NonNull Activity activity) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
    throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
  }
}

RequestManagerRetriever#getSupportRequestManagerFragment

@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
    @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
  SupportRequestManagerFragment current =
      (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  if (current == null) {
    current = pendingSupportRequestManagerFragments.get(fm);
    if (current == null) {
      current = new SupportRequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      if (isParentVisible) {
        current.getGlideLifecycle().onStart();
      }
      pendingSupportRequestManagerFragments.put(fm, current);
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

小结

  • 在Activity下,则创建Fragment,并使用Fragment创建的RequestManager,每个Activity存在且仅存在一个实例

  • 后台线程及非ActivityContext,使用统一的RequestManager公用实例

意义

  • 获取Lifecycle

4.6 初始化RequestManager

@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull androidx.fragment.app.FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current = this.getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        Glide glide = Glide.get(context);
        requestManager = this.factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
        current.setRequestManager(requestManager);
    }

    return requestManager;
}
// Our usage is safe here.
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
RequestManager(
    Glide glide,
    Lifecycle lifecycle,
    RequestManagerTreeNode treeNode,
    RequestTracker requestTracker,
    ConnectivityMonitorFactory factory,
    Context context) {
  
  // ..........此处省略部分代码............
  
  setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

  glide.registerRequestManager(this);
}

  protected synchronized void setRequestOptions(@NonNull RequestOptions toSet) {
    requestOptions = toSet.clone().autoClone();
  }

关键代码:setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

public final class GlideBuilder {
  private RequestOptions defaultRequestOptions = new RequestOptions();
  
    @NonNull
  Glide build(@NonNull Context context) {
        return new Glide(
     		...
        defaultRequestOptions.lock(),
   			...);
  }
}

小结

RequestManager初始化时,会将Glide中的初始RequestOptions进行克隆,并赋值给RequestManager

4.7 RequestBuilder

由上述可知,Glide的结构关系如下,Glide -> RequestManagerRetriever -> RequestManager

其中Glide、RequestManagerRetriever为全局单例

RequestManager为局部单例

而实际完成一次图片加载流程最终则需要用到RequestBuilder,以 load(String)为例:

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

  protected RequestBuilder(
      @NonNull Glide glide,
      RequestManager requestManager,
      Class<TranscodeType> transcodeClass,
      Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    this.transcodeClass = transcodeClass;
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.glideContext = glide.getGlideContext();

    initRequestListeners(requestManager.getDefaultRequestListeners());
    
    // 从requestManager继承requestOptions
    apply(requestManager.getDefaultRequestOptions());
  }
public T apply(@NonNull BaseRequestOptions<?> o) {
  	if (isAutoCloneEnabled) {
    	return clone().apply(o);
  	}
    BaseRequestOptions<?> other = o;

    if (isSet(other.fields, SIZE_MULTIPLIER)) {
      sizeMultiplier = other.sizeMultiplier;
    }
    if (isSet(other.fields, USE_UNLIMITED_SOURCE_GENERATORS_POOL)) {
      useUnlimitedSourceGeneratorsPool = other.useUnlimitedSourceGeneratorsPool;
    }
    ...
    fields |= other.fields;
    options.putAll(other.options);

    return selfOrThrowIfLocked();
  }
// RequestBuilder 继承自BaseRequestOptions
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable{}

小结

  • 每一次请求会新建一个 RequestBuilder
  • RequestBuilder在初始化时使用apply() RequestManager读取RequestOptions配置,且不会改变母体值。
  • RequestBuilder 继承自 BaseRequestOptions

五、结论

  1. 通过Activity Context 发起 Glide 事件,且当前处于主线程时,使用 setDefaultRequestOptions 会在当前Activity长期生效,直至下次重新赋值
  2. 通过非Activity Context发起或者当前处于子线程时,使用setDefaultRequestOptions会在全局长期生效,直至下次重新赋值
  3. 通过apply(BaseRequestOptions)设置,仅对当前本次加载生效
  4. 如果同时设置setDefaultRequestOptionsapply(BaseRequestOptions)先生效前者,然后在此基础上生效后者的改动项
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-27 11:27:30  更:2022-04-27 11:28:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 23:49:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码