Android图片加载框架最全解析(八),面试加分项

RequestOptions options = new RequestOptions() .skipMemoryCache(true); Glide.with(this) .load(url) .apply(options) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

可以看到,只需要调用skipMemoryCache()方法并传入true,就表示禁用掉Glide的内存缓存功能。

接下来我们开始学习硬盘缓存方面的内容。

其实在刚刚学习占位图功能的时候,我们就使用过硬盘缓存的功能了。当时为了禁止Glide对图片进行硬盘缓存而使用了如下代码:

RequestOptions options = new RequestOptions() .diskCacheStrategy(DiskCacheStrategy.NONE); Glide.with(this) .load(url) .apply(options) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

调用diskCacheStrategy()方法并传入DiskCacheStrategy.NONE,就可以禁用掉Glide的硬盘缓存功能了。

这个diskCacheStrategy()方法基本上就是Glide硬盘缓存功能的一切,它可以接收五种参数:

  • DiskCacheStrategy.NONE: 表示不缓存任何内容。

  • DiskCacheStrategy.DATA: 表示只缓存原始图片。

  • DiskCacheStrategy.RESOURCE: 表示只缓存转换过后的图片。

  • DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。

  • DiskCacheStrategy.AUTOMATIC: 表示让Glide根据图片资源智能地选择使用哪一种缓存策略(默认选项)。

其中,DiskCacheStrategy.DATA对应Glide 3中的DiskCacheStrategy.SOURCE,DiskCacheStrategy.RESOURCE对应Glide 3中的DiskCacheStrategy.RESULT。而DiskCacheStrategy.AUTOMATIC是Glide 4中新增的一种缓存策略,并且在不指定diskCacheStrategy的情况下默认使用就是的这种缓存策略。

上面五种参数的解释本身并没有什么难理解的地方,但是关于转换过后的图片这个概念大家可能需要了解一下。就是当我们使用Glide去加载一张图片的时候,Glide默认并不会将原始图片展示出来,而是会对图片进行压缩和转换(我们会在稍后学习这方面的内容)。总之就是经过种种一系列操作之后得到的图片,就叫转换过后的图片。

好的,关于Glide

Android图片加载框架最全解析(八),面试加分项_第1张图片

4硬盘缓存的内容就讲到这里。想要了解更多Glide缓存方面的知识,可以参考 Android图片加载框架最全解析(三),深入探究Glide的缓存机制 这篇文章。

指定加载格式

=================================================================

我们都知道,Glide其中一个非常亮眼的功能就是可以加载GIF图片,而同样作为非常出色的图片加载框架的Picasso是不支持这个功能的。

而且使用Glide加载GIF图并不需要编写什么额外的代码,Glide内部会自动判断图片格式。比如我们将加载图片的URL地址改成一张GIF图,如下所示:

Glide.with(this) .load("http://guolin.tech/test.gif") .into(imageView);

  • 1

  • 2

  • 3

现在重新运行一下代码,效果如下图所示:

也就是说,不管我们传入的是一张普通图片,还是一张GIF图片,Glide都会自动进行判断,并且可以正确地把它解析并展示出来。

但是如果我想指定加载格式该怎么办呢?就比如说,我希望加载的这张图必须是一张静态图片,我不需要Glide自动帮我判断它到底是静图还是GIF图。

想实现这个功能仍然非常简单,我们只需要再串接一个新的方法就可以了,如下所示:

Glide.with(this) .asBitmap() .load("http://guolin.tech/test.gif") .into(imageView);

  • 1

  • 2

  • 3

  • 4

可以看到,这里在with()方法的后面加入了一个asBitmap()方法,这个方法的意思就是说这里只允许加载静态图片,不需要Glide去帮我们自动进行图片格式的判断了。如果你传入的还是一张GIF图的话,Glide会展示这张GIF图的第一帧,而不会去播放它。

熟悉Glide 3的朋友对asBitmap()方法肯定不会陌生对吧?但是千万不要觉得这里就没有陷阱了,在Glide 3中的语法是先load()再asBitmap()的,而在Glide 4中是先asBitmap()再load()的。乍一看可能分辨不出来有什么区别,但如果你写错了顺序就肯定会报错了。

那么类似地,既然我们能强制指定加载静态图片,就也能强制指定加载动态图片,对应的方法是asGif()。而Glide 4中又新增了asFile()方法和asDrawable()方法,分别用于强制指定文件格式的加载和Drawable格式的加载,用法都比较简单,就不再进行演示了。

回调与监听

================================================================

回调与监听这部分的内容稍微有点多,我们分成四部分来学习一下。

1. into()方法

我们都知道Glide的into()方法中是可以传入ImageView的。那么into()方法还可以传入别的参数吗?我们可以让Glide加载出来的图片不显示到ImageView上吗?答案是肯定的,这就需要用到自定义Target功能。

Glide中的Target功能多样且复杂,下面我就先简单演示一种SimpleTarget的用法吧,代码如下所示:

SimpleTarget simpleTarget = new SimpleTarget() { @Override public void onResourceReady(Drawable resource, Transition transition) { imageView.setImageDrawable(resource); } }; public void loadImage(View view) { Glide.with(this) .load("http://guolin.tech/book.png") .into(simpleTarget); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

这里我们创建了一个SimpleTarget的实例,并且指定它的泛型是Drawable,然后重写了onResourceReady()方法。在onResourceReady()方法中,我们就可以获取到Glide加载出来的图片对象了,也就是方法参数中传过来的Drawable对象。有了这个对象之后你可以使用它进行任意的逻辑操作,这里我只是简单地把它显示到了ImageView上。

SimpleTarget的实现创建好了,那么只需要在加载图片的时候将它传入到into()方法中就可以了。

这里限于篇幅原因我只演示了自定义Target的简单用法,想学习更多相关的内容可以去阅读 Android图片加载框架最全解析(四),玩转Glide的回调与监听 。

2. preload()方法

Glide加载图片虽说非常智能,它会自动判断该图片是否已经有缓存了,如果有的话就直接从缓存中读取,没有的话再从网络去下载。但是如果我希望提前对图片进行一个预加载,等真正需要加载图片的时候就直接从缓存中读取,不想再等待慢长的网络加载时间了,这该怎么办呢?

不用担心,Glide专门给我们提供了预加载的接口,也就是preload()方法,我们只需要直接使用就可以了。

preload()方法有两个方法重载,一个不带参数,表示将会加载图片的原始尺寸,另一个可以通过参数指定加载图片的宽和高。

preload()方法的用法也非常简单,直接使用它来替换into()方法即可,如下所示:

Glide.with(this) .load("http://guolin.tech/book.png") .preload();

  • 1

  • 2

  • 3

调用了预加载之后,我们以后想再去加载这张图片就会非常快了,因为Glide会直接从缓存当中去读取图片并显示出来,代码如下所示:

Glide.with(this) .load("http://guolin.tech/book.png") .into(imageView);

  • 1

  • 2

  • 3

3. submit()方法

一直以来,我们使用Glide都是为了将图片显示到界面上。虽然我们知道Glide会在图片的加载过程中对图片进行缓存,但是缓存文件到底是存在哪里的,以及如何去直接访问这些缓存文件?我们都还不知道。

其实Glide将图片加载接口设计成这样也是希望我们使用起来更加的方便,不用过多去考虑底层的实现细节。但如果我现在就是想要去访问图片的缓存文件该怎么办呢?这就需要用到submit()方法了。

submit()方法其实就是对应的Glide 3中的downloadOnly()方法,和preload()方法类似,submit()方法也是可以替换into()方法的,不过submit()方法的用法明显要比preload()方法复杂不少。这个方法只会下载图片,而不会对图片进行加载。当图片下载完成之后,我们可以得到图片的存储路径,以便后续进行操作。

那么首先我们还是先来看下基本用法。submit()方法有两个方法重载:

  • submit()

  • submit(int width, int height)

其中submit()方法是用于下载原始尺寸的图片,而submit(int width, int height)则可以指定下载图片的尺寸。

这里就以submit()方法来举例。当调用了submit()方法后会立即返回一个FutureTarget对象,然后Glide会在后台开始下载图片文件。接下来我们调用FutureTarget的get()方法就可以去获取下载好的图片文件了,如果此时图片还没有下载完,那么get()方法就会阻塞住,一直等到图片下载完成才会有值返回。

下面我们通过一个例子来演示一下吧,代码如下所示:

public void downloadImage() { new Thread(new Runnable() { @Override public void run() { try { String url = "http://www.guolin.tech/book.png"; final Context context = getApplicationContext(); FutureTarget target = Glide.with(context) .asFile() .load(url) .submit(); final File imageFile = target.get(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(context, imageFile.getPath(), Toast.LENGTH_LONG).show(); } }); } catch (Exception e) { e.printStackTrace(); } } }).start(); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

这段代码稍微有一点点长,我带着大家解读一下。首先,submit()方法必须要用在子线程当中,因为刚才说了FutureTarget的get()方法是会阻塞线程的,因此这里的第一步就是new了一个Thread。在子线程当中,我们先获取了一个Application Context,这个时候不能再用Activity作为Context了,因为会有Activity销毁了但子线程还没执行完这种可能出现。

接下来就是Glide的基本用法,只不过将into()方法替换成了submit()方法,并且还使用了一个asFile()方法来指定加载格式。submit()方法会返回一个FutureTarget对象,这个时候其实Glide已经开始在后台下载图片了,我们随时都可以调用FutureTarget的get()方法来获取下载的图片文件,只不过如果图片还没下载好线程会暂时阻塞住,等下载完成了才会把图片的File对象返回。

最后,我们使用runOnUiThread()切回到主线程,然后使用Toast将下载好的图片文件路径显示出来。

现在重新运行一下代码,效果如下图所示。

这样我们就能清晰地看出来图片完整的缓存路径是什么了。

4. listener()方法

其实listener()方法的作用非常普遍,它可以用来监听Glide加载图片的状态。举个例子,比如说我们刚才使用了preload()方法来对图片进行预加载,但是我怎样确定预加载有没有完成呢?还有如果Glide加载图片失败了,我该怎样调试错误的原因呢?答案都在listener()方法当中。

下面来看下listener()方法的基本用法吧,不同于刚才几个方法都是要替换into()方法的,listener()是结合into()方法一起使用的,当然也可以结合preload()方法一起使用。最基本的用法如下所示:

Glide.with(this) .load("http://www.guolin.tech/book.png") .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

这里我们在into()方法之前串接了一个listener()方法,然后实现了一个RequestListener的实例。其中RequestListener需要实现两个方法,一个onResourceReady()方法,一个onLoadFailed()方法。从方法名上就可以看出来了,当图片加载完成的时候就会回调onResourceReady()方法,而当图片加载失败的时候就会回调onLoadFailed()方法,onLoadFailed()方法中会将失败的GlideException参数传进来,这样我们就可以定位具体失败的原因了。

没错,listener()方法就是这么简单。不过还有一点需要处理,onResourceReady()方法和onLoadFailed()方法都有一个布尔值的返回值,返回false就表示这个事件没有被处理,还会继续向下传递,返回true就表示这个事件已经被处理掉了,从而不会再继续向下传递。举个简单点的例子,如果我们在RequestListener的onResourceReady()方法中返回了true,那么就不会再回调Target的onResourceReady()方法了。

关于回调与监听的内容就讲这么多吧,如果想要学习更多深入的内容以及源码解析,还是请参考这篇文章 Android图片加载框架最全解析(四),玩转Glide的回调与监听 。

图片变换

===============================================================

图片变换的意思就是说,Glide从加载了原始图片到最终展示给用户之前,又进行了一些变换处理,从而能够实现一些更加丰富的图片效果,如图片圆角化、圆形化、模糊化等等。

添加图片变换的用法非常简单,我们只需要在RequestOptions中串接transforms()方法,并将想要执行的图片变换操作作为参数传入transforms()方法即可,如下所示:

RequestOptions options = new RequestOptions() .transforms(...); Glide.with(this) .load(url) .apply(options) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

至于具体要进行什么样的图片变换操作,这个通常都是需要我们自己来写的。不过Glide已经内置了几种图片变换操作,我们可以直接拿来使用,比如CenterCrop、FitCenter、CircleCrop等。

但所有的内置图片变换操作其实都不需要使用transform()方法,Glide为了方便我们使用直接提供了现成的API:

RequestOptions options = new RequestOptions() .centerCrop(); RequestOptions options = new RequestOptions() .fitCenter(); RequestOptions options = new RequestOptions() .circleCrop();

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

当然,这些内置的图片变换API其实也只是对transform()方法进行了一层封装而已,它们背后的源码仍然还是借助transform()方法来实现的。

这里我们就选择其中一种内置的图片变换操作来演示一下吧,circleCrop()方法是用来对图片进行圆形化裁剪的,我们动手试一下,代码如下所示:

String url = "http://guolin.tech/book.png"; RequestOptions options = new RequestOptions() .circleCrop(); Glide.with(this) .load(url) .apply(options) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

重新运行一下程序并点击加载图片按钮,效果如下图所示。

可以看到,现在展示的图片是对原图进行圆形化裁剪后得到的图片。

当然,除了使用内置的图片变换操作之外,我们完全可以自定义自己的图片变换操作。理论上,在对图片进行变换这个步骤中我们可以进行任何的操作,你想对图片怎么样都可以。包括圆角化、圆形化、黑白化、模糊化等等,甚至你将原图片完全替换成另外一张图都是可以的。

不过由于这部分内容相对于Glide 3没有任何的变化,因此就不再重复进行讲解了。想学习自定义图片变换操作的朋友们可以参考这篇文章 Android图片加载框架最全解析(五),Glide强大的图片变换功能 。

关于图片变换,最后我们再来看一个非常优秀的开源库,glide-transformations。它实现了很多通用的图片变换效果,如裁剪变换、颜色变换、模糊变换等等,使得我们可以非常轻松地进行各种各样的图片变换。

glide-transformations的项目主页地址是 https://github.com/wasabeef/glide-transformations 。

下面我们就来体验一下这个库的强大功能吧。首先需要将这个库引入到我们的项目当中,在app/build.gradle文件当中添加如下依赖:

dependencies { implementation 'jp.wasabeef:glide-transformations:3.0.1' }

  • 1

  • 2

  • 3

我们可以对图片进行单个变换处理,也可以将多种图片变换叠加在一起使用。比如我想同时对图片进行模糊化和黑白化处理,就可以这么写:

String url = "http://guolin.tech/book.png"; RequestOptions options = new RequestOptions() .transforms(new BlurTransformation(), new GrayscaleTransformation()); Glide.with(this) .load(url) .apply(options) .into(imageView);

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

可以看到,同时执行多种图片变换的时候,只需要将它们都传入到transforms()方法中即可。现在重新运行一下程序,效果如下图所示。

当然,这只是glide-transformations库的一小部分功能而已,更多的图片变换效果你可以到它的GitHub项目主页去学习。

自定义模块

================================================================

自定义模块属于Glide中的高级功能,同时也是难度比较高的一部分内容。

这里我不可能在这一篇文章中将自定义模块的内容全讲一遍,限于篇幅的限制我只能讲一讲Glide 4中变化的这部分内容。关于Glide自定义模块的全部内容,请大家去参考 Android图片加载框架最全解析(六),探究Glide的自定义模块功能 这篇文章。

自定义模块功能可以将更改Glide配置,替换Glide组件等操作独立出来,使得我们能轻松地对Glide的各种配置进行自定义,并且又和Glide的图片加载逻辑没有任何交集,这也是一种低耦合编程方式的体现。下面我们就来学习一下自定义模块要如何实现。

首先定义一个我们自己的模块类,并让它继承自AppGlideModule,如下所示:

@GlideModule public class MyAppGlideModule extends AppGlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { } @Override public void registerComponents(Context context, Glide glide, Registry registry) { } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。

Android图片加载框架最全解析(八),面试加分项_第2张图片

Android高级架构师之路很漫长,一起共勉吧!
ide 4中变化的这部分内容。关于Glide自定义模块的全部内容,请大家去参考 Android图片加载框架最全解析(六),探究Glide的自定义模块功能 这篇文章。

自定义模块功能可以将更改Glide配置,替换Glide组件等操作独立出来,使得我们能轻松地对Glide的各种配置进行自定义,并且又和Glide的图片加载逻辑没有任何交集,这也是一种低耦合编程方式的体现。下面我们就来学习一下自定义模块要如何实现。

首先定义一个我们自己的模块类,并让它继承自AppGlideModule,如下所示:

@GlideModule public class MyAppGlideModule extends AppGlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { } @Override public void registerComponents(Context context, Glide glide, Registry registry) { } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。

[外链图片转存中…(img-8oPkWaAc-1647755997557)]

Android高级架构师之路很漫长,一起共勉吧!

你可能感兴趣的:(程序员,经验分享,面试,开发语言)