Glide 源码解析与原理总结——Glide.with

写作背景

Glide 作为著名的图片加载框架,几乎每一个项目都使用到。笔者尝试通过别人的博客来了解 Glide 原理,但是每次都是看着看着就懵逼了,不是因为别人写的不好,而是 Glide 实在是太复杂了,于是决定自己撸一遍,加深印象。纸上得来终觉浅,绝知此事要躬行。

因为 Glide 太庞大了,做不到面面俱到,所以笔者主要先梳理主干核心原理,后续持续整理。本文源码分析基于4.15.0,就从最基础的调用 Glide.with(context).load(url).into(imageView) 来入手,把主流程最核心的源码整理并且标注、总结。

该篇是Glide.with

Glide.with 源码分析

作用
Glide负责线程池、缓存的构建
RequestManagerRetriever负责获取RequestManager
SupportRequestManagerFragment用户接收和转发生命周期
RequestManager用于请求管理

第1步,从 Glide.with 出发,可以看到Glide.with 有很多重载方法,目的是返回一个RequestManager。(Glide.java)

  //传递Contextpublic static RequestManager with(@NonNull Context context) {return getRetriever(context).get(context);}// 传递FragmentActivitypublic static RequestManager with(@NonNull FragmentActivity activity) {return getRetriever(activity).get(activity);}// 传递Fragmentpublic static RequestManager with(@NonNull Fragment fragment) {return getRetriever(fragment.getContext()).get(fragment);}//传递Viewpublic static RequestManager with(@NonNull View view) {return getRetriever(view.getContext()).get(view);}......

第2步 Glide.with 里面会调用 getRetriever方法,getRetriever() 先会调用 Glide.get(),Glide.get 会调用checkAndInitializeGlide 方法,注意会传递一个APT生成的 GeneratedAppGlideModuleImpl(Glide.java)

  private static RequestManagerRetriever getRetriever(@Nullable Context context) {// 省略...return Glide.get(context).getRequestManagerRetriever();}//双层检测单例模式public static Glide get(@NonNull Context context) {if (glide == null) {//getAnnotationGeneratedGlideModules 内部通过。 //Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl")//拿到GeneratedAppGlideModuleImpl 并且作为参数传递GeneratedAppGlideModule annotationGeneratedModule =getAnnotationGeneratedGlideModules(context.getApplicationContext());synchronized (Glide.class) {if (glide == null) {checkAndInitializeGlide(context, annotationGeneratedModule);}}}return glide;}

最终来到Glide.initializeGlide,GeneratedAppGlideModuleImpl 的作用先记录,后续再慢慢了解,因为 Glide 内容实在太庞大了,每一个细节都要掌握无法梳理主流程(Glide.java)

  private static void initializeGlide(@NonNull Context context,@NonNull GlideBuilder builder,@Nullable GeneratedAppGlideModule annotationGeneratedModule) {//1. 获取应用AppContext,最终是用来构建Glide的Context applicationContext = context.getApplicationContext();//2.这里通过传递进来的 GeneratedAppGlideModuleImpl 调用 getExcludedModuleClassesList<GlideModule> manifestModules = Collections.emptyList();if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {manifestModules = new ManifestParser(applicationContext).parse();}if (annotationGeneratedModule != null&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();Iterator<GlideModule> iterator = manifestModules.iterator();while (iterator.hasNext()) {GlideModule current = iterator.next();if (!excludedModuleClasses.contains(current.getClass())) {continue;}if (Log.isLoggable(TAG, Log.DEBUG)) {Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);}iterator.remove();}}if (Log.isLoggable(TAG, Log.DEBUG)) {for (GlideModule glideModule : manifestModules) {Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());}}//3.这里通过传递进来的 GeneratedAppGlideModuleImpl 获取 RequestManagerRetriever.RequestManagerFactoryRequestManagerRetriever.RequestManagerFactory factory =annotationGeneratedModule != null? annotationGeneratedModule.getRequestManagerFactory(): null;//4.将拿到的工厂添加到GlideBuilderbuilder.setRequestManagerFactory(factory);for (GlideModule module : manifestModules) {module.applyOptions(applicationContext, builder);}//5.这里通过传递进来的 GeneratedAppGlideModuleImpl 调用 applyOptionsif (annotationGeneratedModule != null) {annotationGeneratedModule.applyOptions(applicationContext, builder);}//6.通过GlideBuilder 建造者模式生成 GlideGlide glide = builder.build(applicationContext, manifestModules, annotationGeneratedModule);applicationContext.registerComponentCallbacks(glide);//7. 将构建出来的glide 赋值给 Glide 的静态变量Glide.glide = glide;}

第3步,我们看到了有一个GlideBuilder 来生成Glide,这里有一个地方非常关键:GliderBuilder 来构建Glide,传递的Context 是applicationContext!!!, 你外部使用activity, 这里都会getApplicationContext 传入!!! 

  Glide build(@NonNull Context context,List<GlideModule> manifestModules,AppGlideModule annotationGeneratedGlideModule) {//实例化网络请求线程池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();}//实例化Bitmap对象池if (bitmapPool == null) {int size = memorySizeCalculator.getBitmapPoolSize();if (size > 0) {bitmapPool = new LruBitmapPool(size);} else {bitmapPool = new BitmapPoolAdapter();}}//实例化数组对象池if (arrayPool == null) {arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());}//实例化内存缓存 LruCacheif (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();//实例化RequestManagerRetriever 请求管理类RequestManagerRetriever requestManagerRetriever =new RequestManagerRetriever(requestManagerFactory);//实例化Glidereturn new Glide(context,engine,memoryCache,bitmapPool,arrayPool,requestManagerRetriever,connectivityMonitorFactory,logLevel,defaultRequestOptionsFactory,defaultTransitionOptions,defaultRequestListeners,manifestModules,annotationGeneratedGlideModule,experiments);}

第4步,所以首次调用 Glide.get() 会把 Glide 构建完成,那么调用 Glide 的 getRequestManagerRetriver()就能拿到 RequestManagerRetriver对象。下面看看RequestManagerRetriver.get() 方法,也是有很多重载方法。

 先看下RequestManagerRetriver.get(Context context), 可以看到如果不在主线程或者Context为AppContext,那么调用的是getApplicationManager

  @NonNullpublic 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)) {//1.主线程并且context不为Applicationif (context instanceof FragmentActivity) {//2.如果是FragmentActivityreturn get((FragmentActivity) context);} else if (context instanceof Activity) {//3.如果是Activityreturn get((Activity) context);} else if (context instanceof ContextWrapper&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {//4.如果是ContextWrapper,并且baseContext的AppContext 不为空return get(((ContextWrapper) context).getBaseContext());}}//5.不在主线程或者context为AppContext 调用getApplicationManagerreturn getApplicationManager(context);}

第5步,先看getApplicationManager(context) 构建applicationManager的对象, 这个是App层级的RequestManager。 (RequestManagerReceiver.java)

  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) {//使用AppContext 作为参数拿GlideGlide glide = Glide.get(context.getApplicationContext());applicationManager =factory.build(glide,new ApplicationLifecycle(),//注意:这里是ApplicationLifecyclenew EmptyRequestManagerTreeNode(),context.getApplicationContext());}}}return applicationManager;//返回RequestManager}

 第6步,再看看传递Activity 的情况, 最终会调用FragmentGet 生成一个Fragment 来监听生命周期。这里是最重要的一个方法

  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();//注意:调用FragmentGet,这里会生成一个Fragment 用来监听生命周期return fragmentGet(activity, fm, /* parentHint= */ null, isActivityVisible(activity));}}

第7步 , fragmentGet 方法生成空白的Fragment,该Fragment 是用来管理请求的生命周期的,并且会和RequestManagerFactory工厂生成的RequestManager 绑定。

  private RequestManager fragmentGet(@NonNull Context context,@NonNull android.app.FragmentManager fm,@Nullable android.app.Fragment parentHint,boolean isParentVisible) {//1. 通过getRequestManagerFragment生成一个空白的Fragment,用来管理请求的生命周期,核心方法!!RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);RequestManager requestManager = current.getRequestManager();//2. 如果FragmentManager,为空,就用RequestManagerFactory工厂生成一个并且设给RequestManagerFragmentif (requestManager == null) {Glide glide = Glide.get(context);requestManager =factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);if (isParentVisible) {requestManager.onStart();}current.setRequestManager(requestManager);}//3. 返回RequestManagerreturn requestManager;}

第8步 在看工厂如何生成FragmentManager 之前,先看看如何生成空白的Fragment——RequestManagerFragment,因为这个RequestManagerFragment最终要和RequestManager 绑定的。

  private RequestManagerFragment getRequestManagerFragment(@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {//1. 先缓存中取RequestManagerFragment current = pendingRequestManagerFragments.get(fm);//2.缓存里面没有,再通过 TAG 从FragmentManager 里拿if (current == null) {current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//3. 缓存没有,通过TAG 也拿不到,就初始化一个新的if (current == null) {current = new RequestManagerFragment();current.setParentFragmentHint(parentHint);//4. 先放入缓存,以免下一次Glide请求会再生成一个空白的FragmentpendingRequestManagerFragments.put(fm, current);//5. 通过当前 Activity的 FragmentManager 开始提交添加一个 Fragment容器fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();//6. 这个空白的Fragment 添加到 FragmentManager 成功,通过 Handler 发送一个消息,清理缓存handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();}}return current;}

上面的 getRequestManagerFragment 有一个很重要的点:采用了双重检测保证宿主、空白Fragment、RequestManager 一一对应

第一重保障:使用Map<android.app.FragmentManager, RequestManagerFragment>保存记录集合,解决多个请求只有一个空白Fragment

第二重保障:通过Handler 发送消息让空白的Fragment 马上添加到FragmentManager

FragmentManager 的事务本来就是通过Handler 发送消息来实现,通过Handler 发送消息有可能不会被马上执行,倘若空白的Fragment的消息一直在等待,那么下一次Glide请求就会再生成一个空白的Fragment。而通过Handler 发送删除消息,可以让空白的Fragment添加到FragmentManager马上执行并且清空缓存,这样下一次Glide 请求到来的时候,从FragmentManager的TAG 就能拿到Fragment, 不会再创建。

 第9步,我们再回过头来看看怎样通过工厂RequestManagerFactory 来生成RequestManager的

  private static final RequestManagerFactory DEFAULT_FACTORY =new RequestManagerFactory() {@NonNull@Overridepublic RequestManager build(@NonNull Glide glide,@NonNull Lifecycle lifecycle,@NonNull RequestManagerTreeNode requestManagerTreeNode,@NonNull Context context) {//工厂里也是new 一个 RequestManager return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);}};

  第10步,RequestManager 初始化,监听lifecycle的生命周期。而这个lifecycl就是空白Fragment里的ActivityFragmentLifecycle

  RequestManager(Glide glide,Lifecycle lifecycle,RequestManagerTreeNode treeNode,RequestTracker requestTracker,ConnectivityMonitorFactory factory,Context context) {this.glide = glide;this.lifecycle = lifecycle;this.treeNode = treeNode;this.requestTracker = requestTracker;this.context = context;connectivityMonitor =factory.build(context.getApplicationContext(),new RequestManagerConnectivityListener(requestTracker));glide.registerRequestManager(this);if (Util.isOnBackgroundThread()) {Util.postOnUiThread(addSelfToLifecycle);} else {lifecycle.addListener(this);//this 就是RequestManager 因此RequestManager就会监听Lifecycle生命周期}lifecycle.addListener(connectivityMonitor);defaultRequestListeners =new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());}//Requestmanager 已经监听了空白Fragment的lifecycle@Overridepublic synchronized void onStart() {resumeRequests();//恢复请求targetTracker.onStart();}@Overridepublic synchronized void onStop() {pauseRequests();//暂停请求targetTracker.onStop();}

public class RequestManagerFragment extends Fragment {private static final String TAG = "RMFragment";private final ActivityFragmentLifecycle lifecycle;......@Overridepublic void onStart() {super.onStart();lifecycle.onStart();//转发生命周期}@Overridepublic void onStop() {super.onStop();lifecycle.onStop();//转发生命周期}@Overridepublic void onDestroy() {super.onDestroy();lifecycle.onDestroy();unregisterFragmentWithRoot();//转发生命周期}
}

 到此,可以看到 RequestManager 通过监听空白Fragment 的 lifecycle 的生命周期来管理请求的生命周期的。

Glide.with 原理总结

Glide 初始化并且生成RequestManager,RequestManager 与 空白Fragment 的 lifecycle 生命周期绑定来管理后续的请求。

1) 空白Fragment 持有ActivityFragmentLifecycle,当空白Fragment生命周期改变的时候,调用onStart()、onStop()、onDestroy()——>

2)ActivityFragmentLifecycle 持有LifecycleListener集合,其中RequestManager是其中的一个LifecycleListener,ActivityFragmentLifecycle遍历集合,调用LifecycleListener的onStart()、onStop()、onDestroy()——>

3) RequestManager 实现了LifecycleListener, 在onStart()、onStop()、onDestroy()方法中进行请求的生命周期管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/131085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hackergame2023菜菜WP

文章目录 总结Hackergame2023更深更暗组委会模拟器猫咪小测标题HTTP集邮册Docker for everyone惜字如金 2.0Git? Git!高频率星球低带宽星球小型大语言模型星球旅行日记3.0JSON ⊂ YAML? 总结 最近看到科大在举办CTF比赛&#xff0c;刚好我学校也有可以参加&#xff0c;就玩了…

C#学习系列之静态成员和静态类

C#学习系列之静态成员和静态类 啰嗦静态成员静态类总结 啰嗦 基础学习 静态成员 带有标识为static的字段、方法、属性、构造函数、事件就是静态成员。 class Dog {static string name;//静态成员}name可以被类的所有实例共享&#xff0c;所有实例都访问同一个内存位置。 静态…

Lamport Clock算法

Lamport Clock 是一种表达逻辑时间的逻辑时钟&#xff08;logical clock&#xff09;&#xff0c;能够计算得到历史事件的时间偏序关系。 假设 P0进程是分布式集群中心节点中的监控者&#xff0c;用于统一管理分布式系统中事件的顺序。其他进程在发送消息之前和接受事件消息之后…

路由器基础(十二):IPSEC VPN配置

一、IPSec VPN基本知识 完整的IPSec协议由加密、摘要、对称密钥交换、安全协议四个部分组成。 两台路由器要建立IPSecVPN连接&#xff0c;就需要保证各自采用加密、摘要、对称密钥 交换、安全协议的参数一致。但是IPSec协议并没有确保这些参数一致的手段。 同时&#xff0c;IP…

Java 多线程的三大特性

在JAVA中&#xff0c;线程有原子性、可见性和有序性三大特性。 1.原子性 1.1 定义 对于涉及共享变量的操作&#xff0c;若该操作从其执行线程以外的任意线程来看都是不可分割的&#xff0c;那么我们就说该操作具有原子性。它包含以下两层含义&#xff1a; 访问&#xff08;读、…

【漏洞复现】Django_debug page_XSS漏洞(CVE-2017-12794)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证 说明内容漏洞编号CVE-2017-12794漏洞名称Django_debug page_XSS漏洞漏洞评级影响范…

与AI对话的艺术:如何优化Prompt以获得更好的响应反馈

前言 在当今数字化时代&#xff0c;人工智能系统已经成为我们生活的一部分。我们可以在智能助手、聊天机器人、搜索引擎等各种场合与AI进行对话。然而&#xff0c;要获得有益的回应&#xff0c;我们需要学会与AI进行有效的沟通&#xff0c;这就涉及到如何编写好的Prompt。 与…

开启AWS的ubuntu服务器的root用户登录权限

设置root用户密码 输入以下命令修改root用户密码 sudo passwd root输入以下命令切换到root用户 su root仅允许root用户用密码登录 输入以下命令编辑ssh配置文件 vi /etc/ssh/sshd_config新增以下配置允许root用户登录 PermitRootLogin yes把PasswordAuthentication修改为…

golang相关代码注意点

1. ticker的使用 如果使用 c : time.Tick(1 * time.Nanosecond) 的情况&#xff0c;注意ticker是一个length1的chan。因此如果tick的间隔时间过短&#xff0c;例如图中所示&#xff0c;则会在获取chan之后&#xff0c;chan又被写入下一个触发的element。如果代码只是想触发一…

计算机网络第4章-IPv4

IPv4数据报格式 IPv4数据报格式如下图所示 其中&#xff0c;有如下的关键字段需要特别注意&#xff1a; 版本&#xff08;号&#xff09;&#xff1a; 版本字段共4比特&#xff0c;规定了数据报的IP协议版本。通过查看版本号吗&#xff0c;路由器能确定如何解释IP数据报的剩…

Python爬虫实战-批量爬取下载网易云音乐

大家好&#xff0c;我是python222小锋老师。前段时间卷了一套 Python3零基础7天入门实战https://blog.csdn.net/caoli201314/article/details/1328828131小时掌握Python操作Mysql数据库之pymysql模块技术https://blog.csdn.net/caoli201314/article/details/133199207一天掌握p…

react受控组件与非受控组件

React中的组件可以分为受控组件和非受控组件&#xff1a; 受控组件&#xff1a;受控组件是指组件的值受到React组件状态的控制。通常在组件中&#xff0c;我们会通过state来存储组件的值&#xff0c;然后再将state的值传递给组件的props&#xff0c;从而实现组件的双向数据绑定…

行为型模式-访问者模式

在访问者模式中&#xff0c;我们使用了一个访问者类&#xff0c;它改变了元素类的执行算法。通过这种方式&#xff0c;元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式&#xff0c;元素对象已接受访问者对象&#xff0c;这样访问者对象就…

【星海出品】VUE(三)

node版本查看 nvm list node -v* 16.20.0 (Currently using 64-bit executable) VUE版本查看 package.json 文件 "dependencies": {"vue": "^3.3.4"},VScode 安装 volar 插件有利于开发。 浏览器图标 ico VUE使用一种基于 HTML 的模板语法&#…

MySQL 8.0 主从复制重建流程(从主库数据文件备份恢复)

一、需求描述 MySQL主从复制2台数据库已经存在&#xff0c;因为差异太大的原因&#xff0c;所以需要将主库的数据文件备份在从库进行恢复&#xff0c;重新设置主从复制的关系。 二、准备工作 在开始之前我们需要有主库下面的文件 1.主库MySQL数据目录的备份压缩文件 202311…

MSF暴力破解SID和检测Oracle漏洞

暴力破解SID 当我们发现 Oracle 数据库的 1521 端口时,我们可能考虑使用爆破 SID(System Identifier)来进行进一步的探测和认证。在 Oracle 中,SID 是一个数据库的唯一标识符。当用户希望远程连接 Oracle 数据库时,需要了解以下几个要素:SID、用户名、密码以及服务器的 I…

深入理解WPF中的依赖注入和控制反转

在WPF开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff09;和控制反转&#xff08;Inversion of Control&#xff09;是程序解耦的关键&#xff0c;在当今软件工程中占有举足轻重的地位&#xff0c;两者之间有着密不可分的联系。今天就以一个简单的小例子&…

flink job同时使用BroadcastProcessFunction和KeyedBroadcastProcessFunction例子

背景&#xff1a; 广播状态可以用于规则表或者配置表的实时更新&#xff0c;本文就是用一个欺诈检测的flink作业作为例子看一下BroadcastProcessFunction和KeyedBroadcastProcessFunction的使用 BroadcastProcessFunction和KeyedBroadcastProcessFunction的使用 1.首先看主流…

【华为OD题库-005】选修课-Java

题目 现有两门选修课&#xff0c;每门选修课都有一部分学生选修&#xff0c;每个学生都有选修课的成绩&#xff0c;需要你找出同时选修了两门选修课的学生,先按照班级进行划分&#xff0c;班级编号小的先输出&#xff0c;每个班级按照两门选修课成绩和的降序排序&#xff0c;成…

Linux背景介绍与环境搭建

本章内容 认识 Linux, 了解 Linux 的相关背景学会如何使用云服务器掌握使用远程终端工具 xshell 登陆 Linux 服务器 Linux 背景介绍 发展史 本门课程学习Linux系统编程&#xff0c;你可能要问Linux从哪里来&#xff1f;它是怎么发展的&#xff1f;在这里简要介绍Linux的发展…