Coilは、Kotlinで書かれ、コルーチンをベースにしたAndroid用画像読み込みライブラリです。公式ドキュメントによると、このライブラリはMemory Cache、Disk Cache、ハードウェアアクセラレーションによる変換をサポートしています。Coilは、最小限のAPKサイズ(約150KB)とJetpack Composeとの完全な互換性で際立っています。
重要なポイント
Coil(Coroutine Image Loader)は、完全にKotlinで書かれ、非同期操作にコルーチンを使用するAndroid用画像読み込みライブラリです。ネットワーク、リソース、ファイルシステム、Content Providerからビットマップ画像を読み込むための統一APIを提供し、自動マルチレベルキャッシングを備えています。
GlideやPicassoとは異なり、Coilはコールバックチェーンの代わりにKotlin Coroutinesを使用するため、コードがより直線的で予測可能になります。すべての読み込みとデコード操作は、Dispatchers.IOディスパッチャーを介してバックグラウンドスレッドで実行され、結果は明示的な切り替えなしにメインスレッドに配信されます。
Coilは変換(Round、Blur、Grayscale)、トランジションアニメーション、SVG、GIF、および非標準表示用のカスタムTargetをサポートしています。Google I/O 2023によると、CoilはGlideと並んで公式のJetpack Composeチュートリアルで推奨されています。
ImageLoaderはCoilの主要コンポーネントで、読み込みリクエストの実行とキャッシュの管理を担当します。各インスタンスは、MemoryCache、DiskCache、BitmapPool、およびコルーチンプールへの参照を保持します。デフォルトでは、Coil.imageLoader(context)を介して作成されたシングルトンが使用されます。
ImageRequestは、単一の画像読み込みリクエストを記述するオブジェクトです:データソース(URL、URI、Intリソース)、ターゲットのImageViewまたはTarget、変換、キャッシュ設定、プレースホルダー。ImageRequestはビルダーを介して構築され、柔軟性と可読性を確保します。
val request = ImageRequest.Builder(context)
.data("https://example.com/image.jpg")
.crossfade(true)
.size(512, 512)
.transformations(listOf(RoundedCornersTransformation(12f)))
.memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED)
.target(imageView)
.build()
構築後、ImageRequestはenqueueまたはexecuteを介してImageLoaderに渡されます。enqueueメソッドはコルーチンを起動し、Disposableを返します。これにより、画面を離れるときに読み込みをキャンセルできます。executeメソッドはサスペンド関数で、Resultを直接返します。
ImageLoaderは、MemoryCache、DiskCacheを順次チェックし、両方でミスした場合にのみHttpEngineを介してネットワークリクエストを実行します。読み込み後、バイトはターゲットサイズを考慮してBitmapにデコードされ、変換が適用され、結果は両方のキャッシュに保存されてTargetに渡されます。
Coilはコンポーネントアーキテクチャに基づいて構築されており、依存性注入を介して任意の部分を置き換えることができます。すべてのコンポーネントはImageLoaderFactoryに登録され、ビルダーを介してImageLoaderコンストラクタに渡されます。
ImageLoaderは、すべての読み込み操作のエントリポイントです。各インスタンスには、コルーチンプール、BitmapPool、MemoryCache、DiskCache、およびインターセプターのリストが含まれています。デフォルトでは1つのグローバルインスタンスが作成されますが、単体テスト用に、分離されたキャッシュを持つ個別のインスタンスを作成できます。
MemoryCacheは、LRU(Least Recently Used)ベースのインメモリキャッシュで、デコードされたBitmapオブジェクトを保存します。デフォルトの最大サイズは、利用可能なアプリケーションメモリの25%ですが、32 MBを下回ることはありません。キャッシュキーはURL + サイズ + 変換から形成され、古い画像の取得を防ぎます。
DiskCacheは、生データ(JPEG、PNG、WebP)とデコードされたメタデータ用のファイルベースのキャッシュです。アプリケーションのキャッシュディレクトリに配置され、制限を超えると自動クリーンアップをサポートします。ディスク操作は、ディレクトリと最大サイズの設定を備えたDiskCache.Builderを介して実行されます。
Coilは、ネットワークリクエストを最小限に抑え、画像表示を高速化するマルチレベルキャッシュ戦略を実装しています。各レベルには独自の目的とデータライフタイムがあります。
| レベル | ストレージタイプ | ライフタイム | デフォルトサイズ |
|---|---|---|---|
| Memory Cache | RAM内のBitmap | LRU退避まで | ヒープの25%、32 MBから |
| Disk Cache | JPEG/WebPファイル | 制限超過まで | 250 MB |
| Http Cache | OkHttp応答 | Cache-Controlヘッダーに従う | HTTPクライアントに依存 |
Memory Cacheは、すでにデコードされたBitmapへの瞬時アクセスを提供します。Disk Cacheは、初回読み込み後にネットワークなし(オフラインファースト)でのアプリケーション動作を保証します。OkHttpレベルのHttp Cacheは、ETagおよびIf-Modified-Sinceによる条件付きリクエストを処理します。
キャッシュポリシーは、CachePolicyを介してリクエストごとに設定されます。値はENABLED、READ_ONLY、WRITE_ONLY、DISABLEDの3つです。たとえば、ユーザーアバターの場合、Memory CacheにREAD_ONLY、Disk CacheにENABLEDを設定できます。
Coilは、アプリケーションアーキテクチャに応じて複数の統合方法を提供します。実際のコード例を使って、3つの主要なシナリオを見てみましょう。
loadはImageViewの拡張関数で、1行で画像を読み込む最も簡単な方法です。この関数は、URL、URI、Intリソース、またはFileと、ラムダコンフィギュレーターを介したすべてのオプションパラメータを受け入れます。
imageView.load("https://example.com/photo.jpg") {
crossfade(true)
placeholder(R.drawable.placeholder)
error(R.drawable.error)
size(300, 300)
transformations(CircleCropTransformation())
}
loadメソッドはDisposableを返します。これはonDestroyまたはViewの再利用時にキャンセルできます。これにより、高速なリストスクロール時のメモリリークと不要なネットワークリクエストを防ぎます。
AsyncImageは、宣言的UIで画像を読み込むためのコンポーザブル関数です。任意のデータソースと、プレースホルダー、エラー、サクセスの3つのオプションの状態パラメータを受け入れます。
@Composable
fun NetworkImage(url: String) {
AsyncImage(
model = url,
contentDescription = "ネットワーク画像",
placeholder = ColorPainter(Color.Gray),
error = ColorPainter(Color.Red)
)
}
SubcomposeAsyncImageはより柔軟なバージョンで、コンテンツスロットを通じて読み込み中の表示をカスタマイズできます。これはスケルトン(shimmer)やプログレスバーに便利です。
ImageViewやAsyncImageが適さない場合は、Bitmapを受け取る単一のonSuccessメソッドを持つTargetを実装できます。これはNotification、RemoteViews、OpenGLテクスチャへの読み込みに使用されます。
val target = object : BitmapTarget() {
override fun onSuccess(result: Bitmap) {
notificationRemoteView.setImageViewBitmap(R.id.icon, result)
}
}
imageLoader.enqueue(
ImageRequest.Builder(context)
.data(url)
.target(target)
.build()
)
画像読み込みライブラリの選択はプロジェクトの要件によって異なります。CoilはGlideやPicassoと競合しており、それぞれに強みがあります。主要な特性の比較を表に示します。
| 特性 | Coil | Glide | Picasso |
|---|---|---|---|
| 言語 | Kotlin(100%) | Java + Kotlin | Java |
| APKサイズ | ~150 KB | ~500 KB | ~120 KB |
| コルーチン | 組み込み | なし(コールバック) | なし(コールバック) |
| Jetpack Compose | ネイティブサポート | accompanist経由 | サードパーティ |
| GIF/WebP | はい(組み込み) | はい(組み込み) | いいえ |
| Google推薦 | はい(I/O 2023) | はい | いいえ |
KotlinとJetpack Composeの新しいプロジェクトでは、追加のコルーチン依存関係がゼロでサイズが最小のCoilが自然な選択肢になります。Glideはアニメーションやビデオプレビューを伴う複雑なシナリオで引き続き好まれます。Picassoは機能面で両者に劣りますが、シンプルさでは勝っています。
AndroidプロジェクトへのCoilの追加は、Gradle依存関係を介して行います。追加後、ライブラリはContentProviderを介して自動的にImageLoaderを登録するため、Applicationでの手動初期化は不要です。カスタマイズが必要な場合は、ビルダーを介してカスタムImageLoaderを作成します。
// build.gradle.kts(app module)
dependencies {
implementation("io.coil-kt:coil:2.6.0")
// Jetpack Composeの場合はさらに:
implementation("io.coil-kt:coil-compose:2.6.0")
// SVGサポートの場合:
implementation("io.coil-kt:coil-svg:2.6.0")
// GIFサポートの場合:
implementation("io.coil-kt:coil-gif:2.6.0")
}
ImageLoaderをカスタマイズするには、ImageLoaderFactoryを使用します — Application.onCreateで作成されるシングルトンです。ファクトリでは、キャッシュ制限、HTTPクライアント、カスタムデコーダー、ロギングを設定できます。デフォルトでは、Coilは準備済みの接続プールを持つOkHttpを使用します。
class App : Application(), ImageLoaderFactory {
override fun newImageLoader(): ImageLoader {
return ImageLoader.Builder(this)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(cacheDir.resolve("coil_cache"))
.maxSizeBytes(512 * 1024 * 1024)
.build()
}
.build()
}
}
よくある質問
Coilは、Kotlinでコルーチンを使用して書かれたAndroid用画像読み込みライブラリです。ネットワーク、リソース、ファイルシステムからのビットマップ画像の非同期読み込み、キャッシング、表示に使用されます。
Coilは100%Kotlinで書かれており、Glideのコールバック機構の代わりにコルーチンを使用します。CoilはAPKサイズが小さく(〜150KB vs 〜500KB)、AsyncImageを介したJetpack Composeのネイティブサポートを備えています。
依存関係io.coil-kt:coil:2.6.0をbuild.gradle.ktsに追加します。Jetpack Composeの場合は、io.coil-kt:coil-compose:2.6.0も追加します。ライブラリはContentProviderを介して自動的にImageLoaderを登録します。
CoilはJPEG、PNG、WebP、BMP、SVG(coil-svgモジュール経由)、GIF(coil-gifモジュール経由)をサポートしています。AVIFとHEIF形式は、Android 10+のデバイスでカスタムデコーダーを介してサポートされています。
キャッシュはImageLoader.Builderを介して設定します:memoryCacheはヒープの割合、diskCacheはパスとバイト単位の制限を指定します。キャッシュポリシー(ENABLED、DISABLED、READ_ONLY)はCachePolicyを介してリクエストごとに設定します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。