[译][1.4K+ Star] Kotlin 新秀 Coil VS Glide and Picasso

前言

  • 原标题: 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

  • R8:Coil 下彻底兼容 R8,因此不须要添加任何与 Coil 相关的混淆器规则。
  • Fast:Coil 进行了许多优化,包括内存和磁盘缓存,对内存中的图片进行采样,从新使用位图,自动暂停/取消请求等等。
  • Lightweight:Coil 为你的 APK 增长了 2000 个方法(对于已经使用了 OkHttp 和协程的应用程序),这与 Picasso 至关,明显少于 Glide 和 Fresco。
  • Easy to use:Coil 利用了 Kotlin 的语言特性减小了样版代码。
  • Modern:使用了大量的高级特性,例如协程、OkHttp、和 androidX lifecycle 跟踪生命周期状态的,Coil 是目前惟一支持 androidX lifecycle 的库。

经过这篇文章你将学习到如下内容,将在译者思考部分会给出相应的答案github

  • Kotlin 如何使用一行代码交换两个变量?
  • Coil 和 Glide 和 Picasso 比较,它们优缺点是什么?
  • Kotlin 做为 Android 开发的首选语言,咱们该如何进行选择 Coil、Glide 和 Picasso?
  • 如何在项目中使用 Coil?
  • Coil、Glide 和 Picasso 使用上大比拼?
  • Coil 的动态图片采样是什么?

接下来演示中表格中的数字,可能很难理解,可是为了更好地理解,在最后的部分,会以柱状图清晰的展现每一个库的性能的对比,在译者思考部分会更深刻的分析这三个图片加载库的性能,请耐心多读几遍,应该能够从中学到不少技巧。面试

译文

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 是最慢的。

从这些数字中咱们能够得出几个结论:

  • 有许多场景须要测试,例如,下载大图片,调整图片大小以适应容器等等。所以,我不能说其余状况下的结果可能会有很大的不一样。
  • 正如您所看到的,统计数据是一门包含大量数据的科学,所以对每一个场景进行 10 次测试不足以具体的说明那个库最好,可是咱们能够粗略地了解性能。
  • Glide 彷佛在大多数状况下更快,但数量通常不是很大状况。若是你须要很好地执行,或者你正在下载不少图片,这可能对你来讲是很是有用。此外,若是咱们使用大图片,这些测试的结果可能会改变。
  • Coil 做为图片加载库的新秀,将来它的性能可能会有很大提升,如今只是咱们将它与成熟的图片加载库进行比较的结果。

译者思考

做者从如下场景对 Coil、Glide、Picasso 作了全面的测试。

  • 当缓存为空时,从网络中下载图片的平均时间。

    • 从网络中下载图片所用的时间。 结果:Glide 最快 Picasso 和 Coil 几乎相同。

    • 加载完整的图片列表所用的时间,以及平均时间。 结果:Glide 是最快的,其次是Picasso,Coil是最慢的。

  • 当缓存不为空时,从缓存中加载图片的平均时间。

    • 从缓存中加载图片所用的时间。 结果:Glide 最快,Coil 其次,Picasso 最慢。

    • 加载完整的图片列表所用的时间,以及平均时间。 结果:Glide 和 Coil 几乎相同,Picasso 是最慢的。

图片加载库的选择是咱们应用程序中最重要的部分之一,根据以上结果,若是你的应用程序中没有大量使用图片的时候,我认为使用 Coil 更好,缘由有如下几点:

  • 与 Glide 和 Fresco 相似,Coil 支持位图池,位图池是一种从新使用再也不使用的位图对象的技术,这能够显著提升内存性能(特别是在oreo以前的设备上),可是它会形成一些 API 限制。
  • Coil 是基于 Kotlin 开发的,为 Kotlin 使用而设计的,因此代码一般更简洁更干净。
  • Kotlin 做为 Android 首选语言,Coil 是为 Kotlin 而设计的,Coil 在将来确定会大方光彩。
  • 从 Glide、Picasso 迁移到 Coil 是很是的容易,API 很是的类似。
  • Coil 支持 androidX lifecycle 跟踪生命周期状态,也是是目前惟一支持 androidX lifecycle 的网络图片加载库。
  • Coil 支持动态图片采样,假设本地有一个 500x500 的图片,当从磁盘读取 500x500 的映像时,咱们将使用 100x100 的映像做为占位符。

若是你的是图片类型的应用,应用程序中包含了大量的图片,图片加载的速度是整个应用的核心指标之一,那么如今还不适合使用 Coil。

Coil 涵盖了 Glide、Picasso 等等图片加载库所支持的功能,除此以外 Coil 还有一个功能 动态图片采样

动态图片采样

更多关于图片采样信息能够访问 Coil ,这里简单的说明一下,假设本地有一个 500x500 的图片,当从磁盘读取 500x500 的图片时,将使用 100x100 的映像做为占位符,等待加载完成以后才会彻底显示,用官方的一张动图显示过程以下。

img

这种淡入动画效果,在视觉上体验很是温馨,占位符在主线程上设置,这样能够防止在 ImageView 为空的状况下出现白色闪烁,接下来让咱们来看看如何使用 Coil?Coil、Glide 和 Picasso 使用上大比拼?

如何使用 Coil

添加 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、Glide 和 Picasso 使用上大比拼

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)
复制代码

Kotlin 小技巧

如何实现一行代码交换两个变量?咱们先来回顾一下 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 10 源码分析的文章,了解系统源码,不只有助于分析问题,在面试过程当中,对咱们也是很是有帮助的,若是你同我同样喜欢研究 Android 源码,能够关注我 GitHub 上的 Android10-Source-Analysis,文章都会同步到这个仓库

Android 应用系列

精选译文

工具系列

逆向系列

相关文章
相关标签/搜索