2021-03-22

我们看看将图像加载到android ImageView中时我们面临的问题。

内存不足错误。
将图像缓慢加载到视图中。
UI变得无响应。滚动不流畅。

所有这些问题都可以通过库Glide和Fresco来解决。

Glide库,用于在Android上加载图像。

让我们一一看一下它是如何解决这些问题的

1.内存不足错误
最大的噩梦是所有Android开发人员的生命。为了让我们开心,Glide进行了下采样。下采样意味着将位图(图像)缩放为视图实际需要的较小尺寸。假设我们有一个尺寸为2000 * 2000的图像,但视图尺寸为400 * 400。因此,为什么要加载2000 * 2000的图像,Glide会将位图下采样到400 * 400,然后在视图中显示。

GlideApp.with(context).load(url).into(imageView);
Glide知道imageView的尺寸,因为它将imageView作为参数。

滑行向下采样图像,而无需将整个图像加载到内存中。这样,位图占用的内存更少,并且解决了内存不足错误。

2.加载缓慢
将位图加载到视图中时,缓慢加载是另一个问题。加载缓慢的主要原因之一是,即使视图不在窗口中,我们也不会取消下载,解码位图之类的任务,因此即使我们不需要也有许多任务正在执行,所以它花费时间加载刚好出现在窗口中的实际图像。Glide会处理此问题,它会正确取消所有任务,只加载用户可见的图像。这是使加载快速的一种方法。

Glide知道活动和片段生命周期,因此它知道需要取消哪些图像下载任务。

另一种方法是创建一个内存缓存,这样我们就不必一次又一次地解码图像,因为解码需要时间。Glide创建一个可配置大小的缓存以捕获位图。

它维护两个级别的缓存:

记忆体快取
磁盘缓存
当我们提供Glide的URL时,它将执行以下操作:

它检查带有该URL密钥的图像在内存缓存中是否可用。
如果内存高速缓存中存在位图,它只是通过从内存高速缓存中获取位图来显示它。
如果内存高速缓存中不存在,它将检入磁盘高速缓存。
如果磁盘高速缓存中存在位图,它将从磁盘加载位图,还将其放入内存高速缓存中,并将位图加载到视图中。
如果磁盘高速缓存中不存在该映像,它将从网络下载图像,将其放入磁盘高速缓存中,还将其放入内存高速缓存中,并将位图加载到视图中。
这样,由于直接从内存缓存显示总是更快,因此加载速度更快。

3.无响应的用户界面
UI不响应的最重要原因是应用程序在主线程上执行了太多任务。众所周知,与渲染UI相关的所有任务都是在主线程中完成的。Android每16毫秒更新一次UI。如果您执行任何耗时超过16毫秒的任务,则android必须跳过该更新,也要跳过该帧。因此,跳过帧导致每秒更少的帧。

如果FPS较低,则用户会看到UI滞后,并且无响应。在加载位图时,即使我们在后台加载位图,UI也会滞后。为什么?

原因是位图的大小较大,这使垃圾回收器(GC)的运行非常频繁。

基本规则是-GC运行的时间,您的应用程序未运行。

GC花费时间运行,并且迫使系统跳过许多帧。因此,GC是主要的罪魁祸首。

Glide如何解决这个问题?

使用位图池。

Glide使用此位图池概念来尽可能减少GC调用。

通过使用位图池,它避免了在应用程序中连续分配和释放内存,减少了GC开销,从而使应用程序运行平稳。

如何避免应用程序中内存的连续分配和释放?

通过使用位图的inBitmap属性。(重用位图内存)。

假设我们必须在Android应用程序中加载一些位图。

假设我们必须一张一张地加载两个位图(bitmapOne,bitmapTwo)。当我们加载bitmapOne时,它将为bitmapOne分配内存。然后,如果当我们不再需要bitmapOne时,不要回收该位图(因为回收涉及调用GC)。而是,将此bitmapOne用作bitmapTwo的inBitmap。这样,可以将相同的内存重用于bitmapTwo。

让我们看看代码,它是如何工作的。仔细查看inBitmap属性。

Bitmap bitmapOne = BitmapFactory.decodeFile(filePathOne);
imageView.setImageBitmap(bitmapOne);
// lets say , we do not need image bitmapOne now and we have to set // another bitmap in imageView
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePathTwo, options);
options.inMutable = true;
options.inBitmap = bitmapOne;
options.inJustDecodeBounds = false;
Bitmap bitmapTwo = BitmapFactory.decodeFile(filePathTwo, options);
imageView.setImageBitmap(bitmapTwo);
因此,我们在解码bitmapTwo时重用了bitmapOne的内存。

这样,我们不允许一次又一次地调用GC,因为我们没有离开bitmapOne的引用,而是将bitmapTwo加载到bitmapOne的内存中。

重要的一点是,bitmapOne的大小应等于或大于bitmapTwo,以便可以重新使用bitmapOne的内存。

在重新使用位图内存时,需要考虑一些针对不同Android版本的特定事项,我建议您阅读此项目。

因此,Glide创建了位图的位图池。

可以说,位图池是不再需要的位图列表,但是可重复使用以将新位图加载到同一内存中。

当任何位图可用于回收时,Glide只会将位图推入该位图池中。

当Glide必须加载新的位图时,它只是获得了一个位图,可以重新使用该位图来加载新的位图,以重新使用该位图池中的相同内存。因此,没有回收,没有GC调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值