Android 图片缓存函数库 Glide vs Picasso

@author ASCE1885的 Github 简书 微博 CSDN 知乎
本文由于潜在的商业目的,不开放全文转载许可,谢谢!

mingwang.png-531.3kB

广而告之时间:我的新书《Android 高级进阶》(https://item.jd.com/10821975932.html在京东开始预售了,欢迎订购!

TB2MnqlXH1J.eBjSszcXXbFzVXa_!!1020536390.png-39kB

本文基于《Introduction to Glide, Image Loader Library for Android, recommended by Google》1和《Glide vs. Picasso》2这两篇文章翻译整理而成。

Glide3 和 Picasso4 都是 Android 世界中非常流行的图片加载函数库,Android 应用开发者在职业生涯中至少都应该用过其中一种。这两个函数库都提供了很多特性,经过优化,图片加载速度非常快,而且都在很多实际项目中通过了测试。从某种程度上面讲,Glide 是 Picasso 的一个变种,表面上看,它们的工作原理是一样的,但实际上,无论在图片的下载,缓存还是图片加载进内存的方式,这两个库都存在很大的区别。本文我们就来对比它们的主要区别,看看哪个库是应用开发中的最佳选择。

本文比较的是 Glide v3.7.0 和 Picasso v2.5.2,当你阅读本文时最新版本可能已经发生了变化。

函数库的导入

Picasso 和 Glide 都托管在 jcenter 中,因此,导入到工程中的方式差不多,Picasso 如下所示:

dependencies {
    compile 'com.squareup.picasso:picasso:2.5.2'
}

Glide 如下所示:

repositories {
    mavenCentral() // jcenter() works as well because it pulls from Maven Central
}

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.android.support:support-v4:19.1.0'
}

其中 Glide 依赖于 support-v4,但由于几乎所有项目都会依赖它,所以可以和项目现有的依赖版本共用。

包大小和方法数

从包大小方面看,Glide 差不多是 Picasso 的 3.5 倍,如下图所示:

1-rQe23b0xA6Fpd6zopjx2aQ.png-7.7kB

Picasso 的方法数是 849 个,而 Glide 方法数是 2678 个。这个数字对于 Android DEX 文件的 65535 方法数限制问题来说已经相当大了,在试用过程中一定要记得开启 ProGuard 进行混淆压缩。

1-SE-DjIHhPW8iwf4giJ66aA.png-8.1kB

语法

这两个函数库实现从指定 URL 地址加载图片并显示在 ImageView 上面的语法几乎是一样的,而且都支持渐变动画和基于中间的裁剪(Center Crop)。你当然也可以给 ImageView 设置加载时以及加载失败时的占位图。

Picasso 语法如下:

Picasso.with(context)
    .load(url)
    .centerCrop()
    .placeholder(R.drawable.user_placeholder)
    .error(R.drawable.user_placeholder_error)
    .into(imageView);

Gilde 语法如下:

Glide.with(myFragment)
    .load(url)
    .centerCrop()
    .placeholder(R.drawable.loading_spinner)
    .crossFade()
    .into(myImageView);

Glide 相比 Picasso 的一大优势是它可以和 Activity 以及 Fragment 的生命周期相互协作,我们在调用 Glide.with() 函数时可以将 Activity 或者 Fragment 的实例传进去,这样 Glide 就会自动将图片加载等操作和组件的生命周期例如 onPause()onResume() 关联起来。

with.png-7.2kB

磁盘缓存

这两个函数库都支持从指定 URL 地址将图片下载下来,并缓存到磁盘上,但两者缓存的策略有所不同。

Picasso 将图片下载后会不经压缩直接将图片整个缓存到磁盘中,当需要用到图片时,它会直接返回这张完整大小的图片,并在运行时根据 ImageView 的大小作适配。

Glide 的原理与之不同,它从指定 URL 地址下载图片后会首先根据 ImageView 的大小适配图片,然后将适配后的图片再存储到磁盘中。因此,如果你使用不同大小的 ImageView 加载同一张图片,Glide 将会以不同的分辨率缓存这张图片的两份不同的拷贝。这样可能会增加磁盘缓存的大小,当然好处也是有的,在后面我们会提到。

如前所述,当我们调整 ImageView 的大小时,Picasso 只会缓存完整大小的一张图片,而 Glide 会根据 ImageView 的大小分别缓存对应分辨率的图片。Glide 这种方法的缺点是即使这张图片已经在一个 ImageView 中加载过,如果另一个大小不同的 ImageView 也要加载这张图片,那么这张图片仍然需要重新走一遍流程:到指定的 URL 地址下载,然后根据 ImageView 大小适配,最后缓存到磁盘中。

当然,上面我们说的是默认情况,如果在使用 Glide 时不希望每次都去远程服务器下载完整大小的图片,那么在初始化时可以添加如下 diskCacheStrategy 配置:

Glide.with(myFragment)
    .load(url)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .into(myImageView);

这样配置后,Glide 下次从指定 URL 下载图片,会同时在磁盘上缓存完整的图片和经过大小适配后的图片,下次另一个大小不同的 ImageView 也要加载这张图片,Glide 会直接从磁盘获取完整大小的图片并进行大小适配,缓存后显示在这个 ImageView 中。

内存

默认情况下,Glide 将图片加载进内存时使用的是 RGB_565 的配置,而 Picasso 则使用 ARGB_8888 配置。因此,在对比两者内存占用大小时,为了公平起见我们通过继承 GlideModule 类,并将它加载图片时所用的格式由 RGB_565 修改为 ARGB_8888,类似如下代码所示:

public class MyGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        //
    }
}

当然,为了使这个 GlideModule 生效,我们还需要将这个 GlideModule 在 proguard.pro 文件中 keep 住,如下所示:

-keepnames class com.asce1885.MyGlideModule
// 更通用的方式如下:
// -keep public class * implements com.bumptech.glide.module.GlideModule

接着在 AndroidManifest.xml 文件中注册这个 GlideModule,如下所示:

<manifest ...>
    <!-- ... permissions -->
    <application ...>
        <meta-data
            android:name="com.asce1885.MyGlideModule"
            android:value="GlideModule" />
        <!-- ... activities and other components -->
    </application>
</manifest>

下图就是修改后分别使用 Glide 和 Picasso 在线加载图片时的内存占用:

1--TOjFF8NJ6W7bmHZycjDtw.png-12.5kB

可以看到,在加载同样配置的图片时,Glide 内存占用更少,这从前面的讨论中其实可以猜测到了,Picasso 是将完整大小的图片加载进内存,然后依赖 GPU 来根据 ImageView 的大小来适配并渲染图片,而 Glide 是针对每个 ImageView 适配图片大小后再存储到磁盘的,这样加载进内存的是压缩过的图片,内存占用自然就比 Picasso 要少。Glide 这种做法有助于减少 OutOfMemoryError 的出现。

图片加载的耗时

当从指定 URL 地址加载图片时,这两个函数库都会首先检查图片是否已经在缓存中,如果不存在才去 URL 地址中下载。当我们从远程 URL 地址下载图片时,Picasso 相比 Glide 要快很多。可能的原因是 Picasso 下载完图片后直接将整个图片加载进内存,而 Glide 还需要针对每个 ImageView 的大小来适配压缩下载到的图片,这个过程需要耗费一定的时间。(当然我们可以使用 thumbnail() 来减少压缩的时间,后面会讨论到)

1-P7b1K_pp494aPLZ2sFI3Sw.gif-355.2kB

当然,如果直接从磁盘缓存中加载图片的话,Glide 要比 Picasso 快。这要归功于 Glide 的设计。Picasso 在将图片设置到 ImageView 之前,需要在运行时将图片适配压缩到 ImageView 的大小,这会耗费一定的时间,即使我们使用 .noFade() 来取消图片加载时的渐变效果也是如此。

1-0nIGJyOVgut-kCDMbu3kIg.gif-488.3kB

Picasso 和 Glide 的相同特性

文章开头我们说过,Glide 可以看作是 Picasso 的变种,因此我们可以发现,两者在特性和使用方式上有很多共同点,例如图片大小的适配操作:

// Picasso
.resize(300, 200);

// Glide
.override(300, 200);

图片居中裁剪:

// Picasso
.centerCrop();

// Glide
.centerCrop();

图片的变换:

// Picasso
.transform(new CircleTransform())

// Glide
.transform(new CircleTransform(context))

给 ImageView 设置默认图片和出错时显示的图片:

// Picasso
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)

// Glide
.placeholder(R.drawable.placeholder)
.error(R.drawable.imagenotfound)

可以看到,如果你之前使用过 Picasso,那么想移植代码到 Glide 是非常容易的。

Glide 独有的特性

  • 对 GIF 动画的支持:Glide 能很好的支持 GIF 动画,加载 GIF 图很简单,直接使用 Glide.with(...).load(...) 即可。而且,由于 Glide 能够和 Activity 的生命周期协作,GIF 图片在 onStop() 生命周期函数调用时会停止动画,从而减少动画后台电量的耗费。目前 Picasso 是不支持 GIF 动画的,因此,如果你的应用想支持 GIF 动画的显示,那么只能选择 Glide。
  • 缩略图的支持:使用 Glide,你可以在同一时间加载多张图片到同一个 ImageView 中,例如可以首先加载只有 ImageView 十分之一大小的缩略图,然后在上面再加载完整大小的图片。

总结

从上面的分析可以看出,Glide 继承自 Picasso,而且青出于蓝而胜于蓝,相信通过上面的对比大家应该已经有了自己的选择。

欢迎关注我的微信公众号 ASCE1885,专注与原创或者分享 Android,iOS,ReactNative,Web 前端移动开发领域高质量文章,主要包括业界最新动态,前沿技术趋势,开源函数库与工具等。

猜你喜欢

转载自blog.csdn.net/ace1985/article/details/53223904