[譯][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 應用系列

精選譯文

工具系列

逆向系列

相關文章
相關標籤/搜索