Glide讲解

article/2025/10/12 13:39:08

目录

  • Glide简介
  • Glide的优点
  • Glide的生命周期
  • Glide如何实现图片缓存的
    • 内存缓存实现原理
    • 磁盘缓存实现原理
    • 引入缓存的目的
    • Glide缓存流程
      • 从内存缓存读取总结
      • 从磁盘缓存读取总结
      • 写入磁盘缓存
      • 写入内存缓存
      • 汇总
  • Glide源码总结图解
    • with()
    • load()
    • into()
    • 总结

Glide简介

Glide是Google推荐的一套快速高效的图片加载框架,作者是bumptech,功能强大且使用方便,实际的android应用开发中,有不少的开发者在使用它,今天,就带大家来讲解下Glide的使用及实现的逻辑流程。

地址: Glide源码地址

Glide的优点

  • 使用方便,API简洁。with、load、into三步就可以加载图片
  • 生命周期自动绑定,根据绑定的Activity或者Fragment生命周期管理图片请求
  • 高效的缓存策略,两级内存,两级文件
    A. 支持Memory和Disk图片缓存
    B. Picasso 只会缓存原始尺寸的图片,而 Glide 缓存的是多种规格,也就意味着 Glide 会根据你 ImageView 的大小来缓存相应大小的图片尺寸.
    C. 内存开销小
    默认的 Bitmap 格式是 RGB_565 格式,而 Picasso 默认的是 ARGB_8888 格式,这个内存开销要小一半。

比如你 ImageView 大小是200200,原图是 400400 ,而使用 Glide 就会缓存 200200 规格的图,而 Picasso 只会缓存 400400 规格的。这个改进就会导致 Glide 比 Picasso 加载的速度要快,毕竟少了每次裁剪重新渲染的过程,非常灵活 & 加载速度快

Android关于图片内存计算,共有四种,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存(默认,色彩最细腻=显示质量最高=占用的内存也最大)
RGB_565:每个像素占用2byte内存(8bit = 1byte)
举例说明:一个32位的PNG=ARGB_8888=1204x1024,那么占用空间是:1024x1024x(32/8) = 4,194,304kb=4M左右
在解析图片的时候,为了避免oom和节省内存,最好使用ARGB_4444模式(节省一半的内存空间)

  • 支持多种图片格式(Gif,Webp,Jpg)
  • 有效的内存管理机制

Glide的生命周期

参考下面文章详解,这里只做总结
Android:深入了解图片加载库Glide的生命周期管理(源码分析)

with()方法就是用于绑定生命周期的,with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。调用RequestManagerRetriever的静态get()方法得到一个RequestManagerRetriever对象,这个静态get()方法就是一个单例实现,然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。

RequestManagerRetriever的实例get()方法,传入什么Context参数,Activity参数,Fragment参数等等,实际上只有两种情况而已,即传入Application类型的参数,和传入非Application类型的参数。

  • Application参数:如果传入的是Application对象,那么这里就会调用带有Context参数的get()方法重载,调用getApplicationManager()方法来获取一个RequestManager对象。其实这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,因此Glide并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。
  • 非Application参数:不管传入的是Activity、FragmentActivity、v4包下的Fragment、还是app包下的Fragment,最终的流程都是一样的,那就是会向当前的Activity当中添加一个隐藏的Fragment。因为Glide需要知道加载的生命周期。很简单的一个道理,如果你在某个Activity上正在加载着一张图片,结果图片还没加载出来,Activity就被用户关掉了,那么图片还应该继续加载吗?当然不应该。可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
  • 如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。

在这里插入图片描述

Glide如何实现图片缓存的

参考:Android:深入剖析图片加载库Glide缓存功能(源码分析)

  • Glide的缓存功能设计成 二级缓存:内存缓存 & 硬盘缓存

并不是三级缓存,因为从网络加载 不属于缓存

  • 缓存读取顺序:内存缓存 --> 磁盘缓存 --> 网络

1.内存缓存 默认开启
2.Glide中,内存缓存 & 磁盘缓存相互不影响,独立配置

  • 二级缓存的作用不同:

    • 1.内存缓存:防止应用重复将图片数据 读取到内存当中

只缓存转换过后的图片

    • 2.硬盘缓存:防止应用重复从网络或其他地方重复下载和读取数据

可缓存原始图片 & 缓存转换过后的图片,用户自行设置

Glide的缓存机制使得 Glide具备非常好的图片缓存效果,从而使得具备较高的图片加载效率。

如,在 RecyclerView 上下滑动,而RecyclerView中只要是Glide加载过的图片,都可以直接从内存中读取 & 展示,从而不需要重复从 网络或硬盘上读取,提高图片加载效率。

三级缓存or二级缓存?

在没学习源码之前,我连这个最基本的概念都不确定,以前老是听人说缓存是内存—>磁盘—>网络这样的方式去获取图片资源的,但这就是3级缓存吗?明显不是,这个只是2级缓存;Glide也是按照这种方式获取图片的,但是略有不同,Glide将它的缓存分为2个大的部分,一个是内存缓存,一个是硬盘缓存。其中内存缓存又分为2种,弱引用和Lrucache;磁盘缓存就是DiskLrucache,DiskLrucache算法和Lrucache差不多的,所以现在看起来Glide3级缓存的话应该是WeakReference + Lrucache + DiskLrucache。

内存缓存实现原理

Glide的内存缓存实现是基于:LruCache 算法(Least Recently Used) & 弱引用机制

1.LruCache算法原理:将 最近使用的对象用强引用的方式存储在LinkedHashMap中 ;当缓存满时 ,将最近最少使用的对象从内存中移除
2.弱引用:弱引用的对象具备更短生命周期,因为当JVM进行垃圾回收时,一旦发现弱引用对象,都会进行回收(无论内存充足否)

磁盘缓存实现原理

使用Glide 自定义的DiskLruCache算法

1.该算法基于 Lru 算法中的DiskLruCache算法,具体应用在磁盘缓存的需求场景中
2.该算法被封装到Glide自定义的工具类中(该工具类基于Android 提供的DiskLruCache工具类

Glide5大磁盘缓存策略

  • DiskCacheStrategy.DATA: 只缓存原始图片;
  • DiskCacheStrategy.RESOURCE:只缓存转换过后的图片;
  • DiskCacheStrategy.ALL:既缓存原始图片,也缓存转换过后的图片;对于远程图片,缓存 DATA和 RESOURCE;对于本地图片,只缓存 RESOURCE;
  • DiskCacheStrategy.NONE:不缓存任何内容;
  • DiskCacheStrategy.AUTOMATIC:默认策略,尝试对本地和远程图片使用最佳的策略。当下载网络图片时,使用DATA;对于本地图片,使用RESOURCE;

如果在内存缓存中没获取到数据会通过EngineJob开启线程池去加载图片,这里有2个关键类:DecodeJob 和EngineJob。EngineJob 内部维护了线程池,用来管理资源加载,当资源加载完毕的时候通知回调; DecodeJob是线程池中的一个任务。

磁盘缓存是在EngineJob中的DecodeJob任务中完成的,依次通过ResourcesCacheGenerator、SourceGenerator、DataCacheGenerator来获取缓存数据。ResourcesCacheGenerator获取的是转换过的缓存数据;SourceGenerator获取的是未经转换的原始的缓存数据;DataCacheGenerator是通过网络获取图片数据再按照按照缓存策略的不同去缓存不同的图片到磁盘上。

引入缓存的目的

  • 减少流量消耗,加快响应速度;
    Bitmap 的创建/销毁比较耗内存,可能会导致频繁GC;
  • 使用缓存可以更加高效地加载 Bitmap,减少卡顿。

Glide缓存流程

Glide缓存分为:内存缓存和磁盘缓存,其中内存缓存是由弱引用 + Lrucache组成

在这里插入图片描述

从内存缓存读取总结

在这里插入图片描述

从磁盘缓存读取总结

在这里插入图片描述

写入磁盘缓存

  • Glide将图片写入磁盘缓存的时机:获取图片资源后 、图片加载完成前
  • 写入磁盘缓存又分为:将 原始图片 写入或将 转换后的图片写入磁盘缓存

在这里插入图片描述

写入内存缓存

Glide 将图片写入 内存缓存的时机:图片加载完成后 、图片显示出来前

  • 当 acquired 变量 >0 时,说明图片正在使用,即该图片缓存继续存放到activeResources弱引用缓存中
  • 当 acquired变量 = 0,即说明图片已经不再被使用,就将该图片的缓存Key从 activeResources弱引用缓存中移除,并存放到LruResourceCache缓存中

至此,实现了:

  • 正在使用中的图片 采用 弱引用 的内存缓存
  • 不在使用中的图片 采用 LruCache算法 的内存缓存

在这里插入图片描述

汇总

用一张图将整个Glide 的图片缓存流程汇总
在这里插入图片描述

  • 关于内存缓存 的总结

读取 内存缓存 时,先从LruCache算法机制的内存缓存读取,再从弱引用机制的 内存缓存 读取
写入 内存缓存 时,先写入 弱引用机制 的内存缓存,等到图片不再被使用时,再写入到 LruCache算法机制的内存缓存

  • 关于磁盘缓存 的总结

读取 磁盘缓存 时,先读取 转换后图片 的缓存,再读取 原始图片 的缓存
是否读取 取决于 Glide使用API的设置

写入 磁盘缓存 时,先写入 原始图片 的内存缓存,再写入的内存缓存
是否写入 取决于 Glide使用API的设置

Glide源码总结图解

参考:Android:手把手带你深入图片加载库Glide源码分析

with()

  • 定义:Glide 类中的静态方法,根据传入 不同参数 进行 方法重载

  • 作用:
    1.得到一个RequestManager对象
    2.根据传入with()方法的参数 将Glide图片加载的生命周期与Activity/Fragment的生命周期进行绑定,从而实现自动执行请求,暂停操作

在这里插入图片描述

load()

  • 定义
    由于 .with() 返回的是一个RequestManager对象,所以 第2步中调用的是 RequestManager 类的 load()

  • 作用
    预先创建好对图片进行一系列操作(加载、编解码、转码)的对象,并全部封装到 DrawableTypeRequest对象中。

在这里插入图片描述

into()

  • 作用:

构建网络请求对象 并 执行 该网络请求
即 获取图片资源 & 加载图片并显示

  • 总体逻辑如下:

在这里插入图片描述

  • 详细过程:

在第2步的RequestManager的load()中,最终返回一个DrawableTypeRequest对象

封装好了对图片进行一系列操作(加载、编解码、转码)的对象

但 DrawableTypeRequest类中并没有load()和第3步需要分析的into(),所以load() 和 into() 是在DrawableTypeRequest类的父类中:DrawableRequestBuilder类
继承关系如下
在这里插入图片描述
所以,第三步是调用DrawableRequestBuilder类的 into()完成图片的最终加载

在这里插入图片描述

总结

一图总结Glide的基本功能图片加载的全过程

在这里插入图片描述


http://chatgpt.dhexx.cn/article/i35Vbcvb.shtml

相关文章

Glide详解

现在Android上的图片加载框架非常成熟,从最早的老牌图片加载框架UniversalImageLoader,到后来Google推出的Volley,再到后来的新兴军Glide和Picasso,当然还有Facebook的Fresco。每一个都非常稳定,功能也都十分强大。但是…

Android Glide

1.Glide Glide是Google主导的图片加载开源库。它有很多优势: ①使用简单,链式调用。 ②支持多种图片格式,如Gif、WebP、缩略图、Video等。 ③支持生命周期集成。Glide可以感知调用页面的生命周期,根据Activity或Fragment的生命…

[软件更新]gladder2.0.3.3

介绍 gladder是一个Firefox插件,名字被解释为Great Ladder (Ladder for Great Firewall),目标是帮助人们跨过Great Firewall访问境外被查封的网站。 安装 https://addons.mozilla.org/en-US/firefox/addon/2864 (点击页面中的Install Now按钮) 功能 * 自…

飞机游戏代码(JAVA)

MyGameFrame类: 主要的调用类 package sc.wh.game;import javax.swing.JFrame; import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import sc.wh.game.*; import java.awt.event.KeyAdapte…

基于java的拼图经典游戏(附代码)

拼图游戏是一款经典的益智游戏,游戏开始前图片被随机打乱,空块位于最右下角,玩家通过点击空块周围图片或者按键方式对图片和空块进行相互交换,直到所有图片都回到原位即为游戏胜利。 本次制作的拼图游戏运行界面如下:…

java推箱子游戏源代码_java实现推箱子小游戏(附源码)

先上效果图 可以通过AWSD进行移动和推箱子 自己弄出来的代码玩起来还是很有意思的。 代码一共是三个.java文件,代码内容如下所示 package ss; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.eve…

免费Java游戏源代码素材推荐

家人们,最近我找到了一个很好用的Java游戏源代码免费素材网站 资源贼多,重点是免费!!!白嫖一时爽,一直白嫖一直爽,嘿嘿嘿!!!感兴趣的可以进去看看 接下来就…

java连连看代码_java实现连连看游戏

本文实例为大家分享了java实现连连看游戏的具体代码,供大家参考,具体内容如下 代码会实现共享的,这个是截图 代码: package com.lr.bean; import java.util.Scanner; import java.util.Random; import com.lr.bean.Point; public class Link{public static void main(Strin…

JAVA版扫雷游戏,清晰易懂,注释多

这是一篇关于JAVA的扫雷游戏,所有的图片均用文字代替,代码可直接运行。 文章目录 开发环境一、下载方法二、运行效果展示三、代码部分1.代码如下 总结 开发环境 开发工具:eclipse2021-12 JDK版本:JDK15.0.1 一、下载方法 链接&a…

猜数字游戏(Java源代码)

游戏后台随机生成1-20之间的5个数,未猜中提示“未命中”,继续猜测,猜中提示“运气不错,猜中了”,并输出数据出现的第一次位置源代码: import java.util.Random; import java.util.Scanner;//游戏后台随机…

JAVA实现扫雷游戏

后记:经评论区提醒,发现有两个bug没考虑到,感谢大家的提醒 bug1:绘制雷的时候有可能把两个雷随机到同样的位置。解决方法是在绘制雷的for循环内,rRow和rCol生成后做一个检测即可: /* 绘制地雷 */private v…

Java抽奖小游戏(包含代码)

情景: 假如从50个数字中确定10个中奖号码。 中奖号码要从50个数字中随机产生,中奖号码不可以重复,并对中奖号码进行排序。 解题思路: 首先建立一个长度为n号码的号码库:建立一个数组存放k个中奖号码抽取k个中奖号码。…

贪吃蛇java游戏代码_java实现贪吃蛇游戏代码(附完整源码)

先给大家分享源码,喜欢的朋友点此处下载。 游戏界面 GUI界面 java实现贪吃蛇游戏需要创建一个桌面窗口出来,此时就需要使用java中的swing控件 创建一个新窗口 JFrame frame new JFrame("贪吃蛇游戏"); //设置大小 frame.setBounds(10, 10, 90…

JAVA 实现生命游戏

生命游戏的规则: 生命游戏中,对于任意细胞:每个细胞有两种状态:存活或死亡。每个细胞与以自身为中心的周围八格细胞产生互动。    1.当前细胞为存活状态时,当周围的活细胞低于2个时, 该细胞因孤独而死亡;    2.当…

Java五子棋全代码

用Java编写简单的五子棋 前言 这两天在空闲时间做了个五子棋项目,分享给大家看一下,界面是这样的:        呜呜呜,界面很丑我知道,本人虽有几年PS基础,但知识浅薄,审美观不尽人意&#xff…

五子棋小游戏 java版(代码+详细注释)

游戏展示 这周闲来无事,再来写个五子棋小游戏。基本功能都实现了,包括人人对战、人机对战。界面布局和功能都写的还行,没做到很优秀,但也不算差。如有需要,做个java初学者的课程设计或者自己写着玩玩也都是不错的&…

【Java实现小游戏】飞翔的小鸟(源码)

游戏玩法:通过鼠标点击使小鸟上下移动穿过柱子并完成得分,小鸟碰到柱子或掉落到地面上都会结束游戏。 (游戏内图片) 下面是实现这个游戏的代码: Brid类: package bird;import org.omg.CORBA.IMP_LIMIT;im…

用简单Java代码尝试在控制台写游戏(附源码)

尝试写了一个在Java控制台运行的代码游戏,由于写这个的时候,博主还没学到可视化界面,也没有学到面向对象,甚至没有集合,运用的全是之前C语言的语法,因此应该很容易看懂吧。末尾附上源码。 以下是效果展示 …

Java小游戏练习---超级玛丽代码实现

B站教学视频: 01_超级玛丽_创建窗口_哔哩哔哩_bilibili 素材提取: 【超级会员V2】我通过百度网盘分享的文件:Java游戏项目… 链接:百度网盘 请输入提取码 提取码:k6j1 复制这段内容打开「百度网盘APP 即可获取」 百度网盘 请输入提取码 百度…

java 300行代码 冒险闯关小游戏(代码+讲解)

作为一个男孩子,从小就喜欢晚一些游戏。今天就用java写一个类似马里奥的冒险闯关小游戏,但这也不是一两天能完成的事情,我将会持续更新这个游戏(有什么好的介意也非常欢迎大家提出来,也能在我的基础上自己接着写&#…