coil-compose について
ComposeおよびCompose MultiplatformでCoil 3を使うためのリファレンススキルです。プラットフォームコンテキストの選び方や画像読み込みの性能上の注意点を説明し、サブコンポジションを避ける場面やPainterのサイズ指定を取り上げます。
主な機能
- 01クロスプラットフォームでLocalPlatformContextを使用
- 02共有ImageLoaderの設定
- 03coil-composeとcoreの違い
- 04リスト内でSubcomposeAsyncImageを回避
- 05Painterリクエストのサイズ指定
活用シーン
- 01commonMainでの画像読み込み
- 02クロスプラットフォームImageLoaderの設定
- 03LazyColumnの画像スクロール時のカクつき軽減
- 04Painterによる原寸画像読み込みの防止
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rcosteira79/ android-skills --skill coil-composeインストール後、Claude Code で/coil-composeを入力して読み込まれたか確認します。
詳細
Compose と Compose Multiplatform 向け Coil 3
このリファレンスでは、KMP 固有の内容と 2 つのパフォーマンス上の注意点を扱います。AsyncImage/SubcomposeAsyncImage/ImageRequest/placeholder/error/contentDescription/共有 ImageLoader の基本については説明しません。
KMP:LocalContext ではなく LocalPlatformContext
Coil 3 は完全なマルチプラットフォーム対応です。AsyncImage/SubcomposeAsyncImage/rememberAsyncImagePainter は commonMain で同一であり、expect/actual は不要です。変更点は 1 つだけです。LocalContext.current(Android 専用であり、commonMain ではコンパイルエラーになります)ではなく、LocalPlatformContext.current を使用してください。Android では android.content.Context に、それ以外のターゲットでは PlatformContext.INSTANCE に解決されます。
// commonMain — works on all platforms
AsyncImage(
model = ImageRequest.Builder(LocalPlatformContext.current).data(url).crossfade(true).build(),
contentDescription = "User avatar",
modifier = Modifier.size(48.dp).clip(CircleShape),
)
シングルトンの設定(KMP): アプリのライフサイクルの早い段階で SingletonImageLoader.setSafe { ImageLoader.Builder(it).crossfade(true).build() } を一度呼び出すか、imageLoader を明示的に渡してください。coil-compose と coil-compose-core の違い: coil-compose では、imageLoader 引数を指定しない AsyncImage がシングルトンを自動的に使用します。一方、coil-compose-core では imageLoader パラメーターが必須です(シングルトンを便利に使う仕組みはありません)。必要に応じて、プラットフォーム用のネットワークエンジンを追加してください(例:KMP 向けの coil-network-ktor3)。
2 つのパフォーマンス上の注意点
SubcomposeAsyncImage は通常のコンポジションより大幅に遅いため、LazyColumn/LazyRow 内では絶対に使用しないでください。 アイテムごとにサブコンポジションが作成され、スクロール中にそのオーバーヘッドが蓄積して、目に見えるジャンクを引き起こします。リスト内の読み込み中/エラー状態をカスタマイズする場合は、代わりに placeholder/error パラメーターを指定した AsyncImage を使用してください。同じ見た目を実現でき、サブコンポジションも発生しません。
rememberAsyncImagePainter はレイアウト制約から表示サイズを推測しません。明示的な .size() を指定しないと、画像を元の寸法で読み込みます(64dp で表示する 4000×3000 の写真でも、メモリ上ではビットマップ全体を占有するため、50 アイテムのリストでは OOM が発生します)。Painter がどうしても必要な場合(Canvas、Icon、カスタム描画)にのみ使用し、必ず .size() を渡してください。それ以外の場合は、自動でサイズを調整する AsyncImage を使用してください。
// only when a Painter is genuinely required — explicit size is mandatory
val painter = rememberAsyncImagePainter(
ImageRequest.Builder(LocalPlatformContext.current).data(url).size(Size(128, 128)).build(),
)
Image(painter = painter, contentDescription = null)