Android 图片加载框架Glide源码详解

我们看Glide的源码从Glide类入手,使用的时候我们先调用的with方法,源码中with有3个多载的方法:下图翻译过来就是activity用FragmentActivity Applicationcontext用 with(Context)还有一个with(View)的

殊途同归,最后都是调用了getRetriever(context).get(context),我们看看最后的get(context)方法 ,如下图, 这就大致分成两类一种是ApplicationContext, 一种是activity,fragment ,两种lifecycle生命周期,下图是证明:

为什么要区分Applicationlifecycler和Activitylifecycler 呢?

在Glide中,区分Application Lifecycle和Activity Lifecycle主要是为了更好地管理图像加载和缓存的策略。

Application Lifecycle:在Android应用程序中,Application Lifecycle指的是从应用程序启动到关闭的整个生命周期。在这个生命周期中,Glide可以根据应用程序的整体状态来调整其行为。例如,当应用程序处于后台时,Glide可以减少图像加载的频率或暂停加载,以节省资源和电量。而在应用程序重新进入前台时,Glide可以恢复正常的加载行为。

Activity Lifecycle:Activity Lifecycle指的是一个Activity从启动到销毁的周期。在这个生命周期中,Glide可以与Activity的各个生命周期回调方法进行交互,以便在适当的时机加载和显示图像。例如,当Activity在用户面前时(onResume()调用后),Glide可以在该时机加载并显示图像。而在Activity被用户离开时(onPause()调用后),Glide可以暂停加载或释放一些资源。

通过区分这两个生命周期,Glide可以更精细地控制图像加载和缓存的行为,以适应不同场景和应用程序需求。这有助于提高应用程序的性能、节省资源并提高用户体验。

同时glide的初始化也是在这里getRetriever方法中完成的

从图上我们也可以看出来with 方法返回的是RequestManager, 里面有一个TargetTracker 跟踪view target的 ,每当RequestManage生命周期变化时,通知各个view。

现在是不是能想到,之前聊的lifecycler两种生命周期和它对上了,Application和activity等他们的生命周期会调用manager的,manager再通知各个view,贯通了整个框架。给你们看一下添加的listener

RequestManager集合了glide的要用的各种类,对Request进行管理,其中里面的load方法返回的是RequestBuilder,这里的load实际上还是调用RequestBuilder里面的load

load的方法还是挺空的,重点是赋值这个model 图片地址。

从下图可以看出,RequestBuilder这个类才是Builder设计模式的主类,我们使用中最后的into方法返回的是Target,大部分逻辑都在这个方法里面了, buildRequest就是重点,

然后走的是obtainRequest

SingleRequest.obtain

SingleRequest获得后,在begin方法中

有个onSizeReady

主角登场,engine.load方法。

里面有glide加载缓存的逻辑

下图可以看到是先加载内存中的处理过的resource,里面是一个hashmap维护的key resource 键值对的缓存,第二个就是采取了lru算法的采用linkedhashmap的内存数据

然后是调用了waitForExistingOrStartNewJob方法,开始decodeJob 解码工作

runWrapped()方法, runGenerators方法, currentGenerator.startNext()

值得看的是currentGenerate是下图中3个的哪一个呢,从逻辑上看3个会依次遍历,分别是先处理过的resource缓存,然后是data缓存,最后是Source网络加载, 这也是glide的三级缓存。我们只讲一个SourceGenerator,里面也有下载图片的modelloader,其他两个的逻辑差不多,不再赘述了。下面就要开始讲根据model,data找modelloader的逻辑了,做好心理准备,不简单,网上大都是一笔带过(因为他们也弄不清,的确有点复杂,绕来绕去),好不容易全网找到一篇,不知道是他的版本旧的,还是他理解的不对,珍惜吧,我认为是全篇最难的地方了。

3个也都会调用loadData.fetcher.loadData,重点是找到这个loadData


handles 过滤筛选出可以处理我们数据类型model的modelloader ,比如我们图片用的是https的String

String的有3个,但如果你是http开头的网络url的话就只有StringLoader.Streamfactory了,可以看他们3个各种的handles

还没完,用Uri InputStream 来代替执行

有5个,而符合我们http或https的就只有append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())了

又转为GlideUrl.class, InputStream.class,我们再去工厂里面找,经过三次我们才真正找到 HttpGlideUrlLoader.Factory()

想起前面sourceGenerate 的 loaddata.fetcher.loaddata没有,就是这个HttpUrlFetcher

下载图片的找到了,拿到数据之后的data的回调就是listener来做了,比较简单就不说了,至此难点讲完了。

然后我们跳回SingleRequest类中

然后你会发现这个begin是由 RequestManager.into方法中的requestManager.track(target, request);发起的

随后我们看一下as相关的方法,有三个,其实是两个GifDrawable和drawable是一类,还有一类是bitmap,那么glide为什么将drawable和bitmap 分开呢

看下图,因为glide把两种分成了两个类target view,view的setImageBitmap 和setImageDrawable两个不同的方法加载Resource。

再有就是RequestBuilder关于apply函数加载options

RequestOptions options = new RequestOptions()

复制代码
            .placeholder(R.mipmap.loading)                //加载成功之前占位图

            .error(R.mipmap.loading)                    //加载错误之后的错误图

            .override(400,400)                                //指定图片的尺寸

            //指定图片的缩放类型为fitCenter (等比例缩放图片,宽或者是高等于ImageView的宽或者是高。)

            .fitCenter()

            //指定图片的缩放类型为centerCrop (等比例缩放图片,直到图片的狂高都大于等于ImageView的宽度,然后截取中间的显示。)

            .centerCrop()

            .circleCrop()//指定图片的缩放类型为centerCrop (圆形)

            .skipMemoryCache(true)                            //跳过内存缓存

            .diskCacheStrategy(DiskCacheStrategy.ALL)        //缓存所有版本的图像

            .diskCacheStrategy(DiskCacheStrategy.NONE)        //跳过磁盘缓存

            .diskCacheStrategy(DiskCacheStrategy.DATA)        //只缓存原来分辨率的图片

            .diskCacheStrategy(DiskCacheStrategy.RESOURCE)    //只缓存最终的图片

             .dontTransform()  //禁用图形变换功能,这个方法时全局的,导致其他地方的图片也不可进行图形变换了,慎用.

            .dontAnimate();//跳过动画

Glide还实现了ComponentCallbacks2接口,这个是内存监测的,我们的Activity等也都会用它

在内存不足的时候,对自己占用的进行清理。

最后用图来总结吧,没有捋顺的童鞋可以参考看看,有其他疑问的,咱评论区见了。

相关推荐
传奇开心果8 分钟前
【探秘 Jetpack Compose 框架深水区】 第8课:rememberSaveable 的边界在哪里?——Bundle、Saver 与什么值得跨进程存活
android·kotlin
Frankie_stand1 小时前
测试自动化实战指南:从脚本化、自动判据到 CI 集成的完整落地路径
android·ci/cd·自动化
恋猫de小郭2 小时前
Flutter 大小核优化又被回滚,然后又开新提案?
android·前端·flutter
Kapaseker2 小时前
领导问我 Kotlin 的 Nothing 是什么?
android·kotlin
韩曙亮3 小时前
【错误记录】安卓 adb 调试 5037 端口占用排查 ( adb 的三层结构 | 找出本机占用 5037 的进程 )
android·数据库·adb·安卓·错误记录
三少爷的鞋4 小时前
不改变异步本质,只改变代码组织:Telegram 项目的 Kotlin 协程实践
android
好的佩奇13 小时前
蓝牙之广播与扫描
android·flutter·蓝牙
传奇开心果编程15 小时前
【Jetpack Compose娓娓道来】第36课:焦点管理与键盘输入——让遥控器、键盘和输入法都“找得到北”
android·kotlin·移动开发·交互·android jetpack·ui框架·声明式ui
hai_android15 小时前
AudioTrack 深度解析:从原理到实战
android·java·kotlin
红尘伴蝶舞16 小时前
从秒开优化到连环崩溃:深入剖析 ViewPager2 在常驻 DialogFragment 中的复用陷阱与自愈方案
android·kotlin