- 原标题: Coil vs Picasso vs Glide: Get Ready… Go!
- 原文地址: proandroiddev.com/coil-vs-pic…
- 原文做者:Miguel Ángel Ruiz López
- 这篇文章在 Medium 上到目前为止得到了 1.4K+ Star,很是好的一篇文章
Coil 做为图片加载库的新秀,和 Glide、Picasso 这些老牌图片库相比,它们的优缺点是什么以及 Coil 将来的展望?先来了解一下什么是 Coil。android
Coil 是基于 Kotlin 开发的首个图片加载库,来自 Instacart 团队,来看看官网对它的最新的介绍。git
经过这篇文章你将学习到如下内容,将在译者思考部分会给出相应的答案github
接下来演示中表格中的数字,可能很难理解,可是为了更好地理解,在最后的部分,会以柱状图清晰的展现每一个库的性能的对比,在译者思考部分会更深刻的分析这三个图片加载库的性能,请耐心多读几遍,应该能够从中学到不少技巧。面试
Coil 做为图片库的新秀,愈来愈受欢迎了,可是为何会引发这么多人的关注?在当今主流的图片加载库环境中 Coil 是一股清流,它是轻量级的,由于它使用了许多 Android 开发者已经在他们的项目中包含的其余库(协程、Okhttp)。算法
当我第一次看到这个库时,我认为这些都是很好的改进,可是我很想知道和其余主流的图片加载库相比,这个库能带来哪些好处,这篇文章的主要目的是分析一下 Coil 的性能,接下来咱们来对比一下 Coil、 Glide 和 Picasso。编程
为了弄清楚这些库的性能如何,咱们分别用它们实现了一个应用程序,这是一个简单的应用程序,它下载 10 张图片并以网格布局显示它们,以下图所示。数组
全部图片都是在同一时间可见的,几乎是在同一时间被请求的,所以,能够认为它们是并行加载。缓存
另外一个须要测试的重要点是第一次加载图片和从缓存中加载它们所花费的时间,已经进行了屡次测试,覆盖了上面的场景。安全
咱们开始第一个场景,当缓存为空时,从网络中下载图片。性能优化
Glide
在下面的表中,您能够看到当缓存为空时,从网络中下载图片所用的时间。注意,这些时间是测试 10 次以后的平均值。
下表展现了加载完整的图片列表所需的时间,以及平均时间。
Picasso
Picasso 的测试和 Glide 相同,当缓存为空时,从网络中下载图片,测试 10 次左右所用的时间的平均值。
以及加载完整的图片列表所须要的时间,以及平均时间。
Coil
如今来看一下今天主角 Coil ,和 Picasso、Glide 作相同的测试,当缓存为空时,从网络下载 10 次左右所用的时间的平均值。
以及加载完整的图片列表所需的时间,以及平均时间。
如今开始另一个场景测试,当缓存不为空时,加载图片所须要的时间。
Glide
从缓存中加载图片所用时间,以下表所示。
从缓存中加载完整的图片列表所需的时间,以及平均时间。
Picasso
测试用例和 Glide 相同,从缓存中加载图片所用时间,以下表所示。
以及从缓存中加载完整的图片列表所需的时间,以及平均时间。
Coil
最后咱们来看一下 Coil 如何呢,从缓存中加载图片所用时间,以下表所示。
一样的从缓存中加载完整的图片列表所需的时间,以及平均时间。
为了更好地理解咱们在测试中获得的结果,咱们能够从下面图表中看到这些数字,反应了从网络下载每一个图片时的结果。
Glide 最快 Picasso 和 Coil 几乎相同。
可是当咱们从缓存中加载的时候,正如你在下面的图片中看到的,在大多数状况下,Glide 最快,Coil 其次,Picasso 最慢。
另外一个重要的测试加载完整的图片列表所花费的时间,这些数字很是重要,由于这是用户等待看到整个图片列表的时间。当图片从网络加载时,Glide 是最快的,其次是Picasso,Coil是最慢的。
从缓存加载的结果是不一样的。Glide 和 Coil 几乎相同,Picasso 是最慢的。
从这些数字中咱们能够得出几个结论:
做者从如下场景对 Coil、Glide、Picasso 作了全面的测试。
当缓存为空时,从网络中下载图片的平均时间。
从网络中下载图片所用的时间。 结果:Glide 最快 Picasso 和 Coil 几乎相同。
加载完整的图片列表所用的时间,以及平均时间。 结果:Glide 是最快的,其次是Picasso,Coil是最慢的。
当缓存不为空时,从缓存中加载图片的平均时间。
从缓存中加载图片所用的时间。 结果:Glide 最快,Coil 其次,Picasso 最慢。
加载完整的图片列表所用的时间,以及平均时间。 结果:Glide 和 Coil 几乎相同,Picasso 是最慢的。
图片加载库的选择是咱们应用程序中最重要的部分之一,根据以上结果,若是你的应用程序中没有大量使用图片的时候,我认为使用 Coil 更好,缘由有如下几点:
若是你的是图片类型的应用,应用程序中包含了大量的图片,图片加载的速度是整个应用的核心指标之一,那么如今还不适合使用 Coil。
Coil 涵盖了 Glide、Picasso 等等图片加载库所支持的功能,除此以外 Coil 还有一个功能 动态图片采样。
更多关于图片采样信息能够访问 Coil ,这里简单的说明一下,假设本地有一个 500x500 的图片,当从磁盘读取 500x500 的图片时,将使用 100x100 的映像做为占位符,等待加载完成以后才会彻底显示,用官方的一张动图显示过程以下。
这种淡入动画效果,在视觉上体验很是温馨,占位符在主线程上设置,这样能够防止在 ImageView 为空的状况下出现白色闪烁,接下来让咱们来看看如何使用 Coil?Coil、Glide 和 Picasso 使用上大比拼?
添加 Coil 依赖
implementation "io.coil-kt:coil:0.11.0"
复制代码
在 App moudule 下 build.gradle 文件中添加以下代码
kotlinOptions {
jvmTarget = "1.8"
}
复制代码
在项目中调用你须要的代码,这里汇总了 Coil 全部使用方式
// 将图片加载到 ImageView 中, 并开启图片采样
// 用到了 Kotlin 的高级特性扩展,调用更加简单
imageView.load("https://www.example.com/image.jpg"){
crossfade(true)
}
inline fun ImageView.load(
uri: String?,
imageLoader: ImageLoader = Coil.imageLoader(applicationContext),
builder: LoadRequestBuilder.() -> Unit = {}
): RequestDisposable {
return imageLoader.load(context, uri) {
target(this@load)
builder()
}
}
// Coil 支持 Uri,File, String,HttpUrl, Bitmap, Drawable, DrawableId
imageView.load(R.drawable.ic_launcher_background)
imageView.load(File("/path/to/image.jpg"))
imageView.load("content://com.android.externalstorage/image.jpg")
// ......
// Coil 提供了四种转换: 模糊,圆形剪裁,灰度和圆角
imageView.load("https://www.example.com/image.jpg") {
crossfade(true)
placeholder(R.drawable.ic_launcher_background)
transformations(CircleCropTransformation())
}
// Coil 是一个 object 单例
val imageLoader1 = Coil.imageLoader(applicationContext)
// 能够建立 或者 调用第三方库(Koin) 注入本身的实例。
val imageLoader2 = ImageLoader(applicationContext)
// 在某些状况下,须要远程下载而后进行回调
var request = LoadRequest.Builder(applicationContext)
.data("https://www.example.com/image.jpg")
.target { drawable ->
// Handle the successful result.
}
.build()
imageLoader2.execute(request)
复制代码
Coil 基于 Kotlin 而设计,天然也拥有了 Kotlin 的高级函数的特性,使用比 Glide 和 Picasso 要简单不少。
基本使用
// Coil - 用到了 Kotlin 的高级特性扩展,一行代码加载图片
imageView.load(url)
// Glide
Glide.with(context)
.load(url)
.into(imageView)
// Picasso
Picasso.get()
.load(url)
.into(imageView)
复制代码
后台线程
// Coil:无阻塞和线程安全
val imageLoader = Coil.imageLoader(context)
val request = GetRequest.Builder(context)
.data(url)
.size(width, height)
.build()
val drawable = imageLoader.execute(request).drawable
// Glide:阻塞当前线程,必定不能从主线程调用
val drawable = Glide.with(context)
.load(url)
.submit(width, height)
.get()
// Picasso:阻塞当前线程,必定不能从主线程调用
val drawable = Picasso.get()
.load(url)
.resize(width, height)
.get()
复制代码
自动检测 scaleType
imageView.scaleType = ImageView.ScaleType.FIT_CENTER
// Coil:自动检测 scaleType
imageView.load(url) {
placeholder(placeholder)
}
// Glide
Glide.with(context)
.load(url)
.placeholder(placeholder)
.fitCenter()
.into(imageView)
// Picasso
Picasso.get()
.load(url)
.placeholder(placeholder)
.fit()
.into(imageView)
复制代码
如何实现一行代码交换两个变量?咱们先来回顾一下 JAVA 的作法
int a = 1;
int b = 2;
// JAVA - 中间变量
int temp = a;
a = b;
b = temp;
System.out.println("a = "+a +" b = "+b); // a = 2 b = 1
// JAVA - 加减运算
a = a + b;
b = a - b;
a = a - b;
System.out.println("a = " + a + " b = " + b); // a = 2 b = 1
// JAVA - 位运算
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("a = " + a + " b = " + b); // a = 2 b = 1
// Kotlin
a = b.also { b = a }
println("a = ${a} b = ${b}") // a = 2 b = 1
复制代码
致力于分享一系列 Android 系统源码、逆向分析、算法、翻译相关的文章,目前正在翻译一系列欧美精选文章,请持续关注,除了翻译还有对每篇欧美文章思考,若是对你有帮助,请帮我点个赞,感谢!!!期待与你一块儿成长。
因为 LeetCode 的题库庞大,每一个分类都能筛选出数百道题,因为每一个人的精力有限,不可能刷完全部题目,所以我按照经典类型题目去分类、和题目的难易程度去排序
每道题目都会用 Java 和 kotlin 去实现,而且每道题目都有解题思路,若是你同我同样喜欢算法、LeetCode,能够关注我 GitHub 上的 LeetCode 题解:Leetcode-Solutions-with-Java-And-Kotlin,一块儿来学习,期待与你一块儿成长
正在写一系列的 Android 10 源码分析的文章,了解系统源码,不只有助于分析问题,在面试过程当中,对咱们也是很是有帮助的,若是你同我同样喜欢研究 Android 源码,能够关注我 GitHub 上的 Android10-Source-Analysis,文章都会同步到这个仓库