はじめに
インターネット上にある画像をAndroidのアプリ内で表示したい場合、Coilなどのネットワーク画像ライブラリを使用することが一般的です。
本記事では、そのような画像ライブラリのシンプル版を自作してみたいと思います。
処理の流れ
ネットワーク上の画像を表示するまでの処理は、以下の3段階に分かれます。
1. インターネットから画像のデータを取得する
HTTPクライアントとしてOkHttpを使用します。レスポンスのボディからBufferedSourceを取得し、結果として返します。
object ImageRequester {
private val client = OkHttpClient()
suspend fun request(url: String): BitmapBufferedSource {
return withContext(Dispatchers.IO) {
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
BitmapBufferedSource(response.body?.source()!!)
}
}
}
ちなみに、Androidではネットワークアクセスをメインスレッドで行うとNetworkOnMainThreadExceptionが発生するため注意が必要です。
2. 取得した画像データをBitmapに変換する
取得した画像データをandroid.graphics.Bitmapに変換します。ここではBitmapFactory#decodeStream(InputStream)を使用します。
data class BitmapBufferedSource(
val bufferedSource: BufferedSource
) {
fun toBitmap(): Bitmap {
return BitmapFactory.decodeStream(bufferedSource.inputStream())
}
}
3. BitmapからPainterを作成し画面に表示する
Bitmapを作成できたら、Composeで画像を表示するためにPainterを作成します。ここではBitmapPainterを使用します。
@Composable
fun rememberNetworkImagePainter(url: String): Painter {
var currentImageBitmap: ImageBitmap? by remember { mutableStateOf(null) }
LaunchedEffect(url) {
val bitmapBufferedSource = ImageRequester.request(url)
val bitmap = bitmapBufferedSource.toBitmap()
val imageBitMap = bitmap.asImageBitmap()
currentImageBitmap = imageBitMap
}
return remember(currentImageBitmap) {
val imageBitmap = currentImageBitmap
if (imageBitmap == null) {
EmptyPainter
} else {
BitmapPainter(imageBitmap)
}
}
}
作成したPainterをImageで使用します。
@Composable
internal fun NetworkImage(
url: String,
modifier: Modifier = Modifier
) {
Image(
painter = rememberNetworkImagePainter(url),
contentDescription = null,
modifier = modifier,
)
}
できました!
約50行程度のコードで、ネットワーク上の画像を表示することができました
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F56635%2Fe10f7048-319a-dcf5-1e06-32022dde6f06.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=7271691206c7d455ce0a945f7da114dc)
なぜ画像ライブラリを使用するべきか
ここまで読んで、意外と簡単にComposeでネットワーク画像を表示できることが分かったと思います。それでも画像ライブラリを使用するべき理由がいくつかあります。
キャッシュ
画像ライブラリはメモリキャッシュやディスクキャッシュを自動で管理し、不要なネットワークアクセスを削減します。一度ロードした画像を再取得せず即座に表示できるため、スクロール時のパフォーマンス向上にもつながります。
様々なフォーマット
画像ライブラリを使用すると、JPEGやPNGだけでなく、GIFやSVGなどのフォーマットも簡単に扱えます。Coilの場合、coil-gif、coil-svg、coil-videoを利用できます
マルチプラットフォーム
Coil v3からはKotlin Multiplatform(Compose Multiplatform)に対応し、Android以外のプラットフォームでも動作するようになりました。
状態管理
画像の読み込みにはローディング、エラー、プレースホルダーなどの状態管理が必要です。画像ライブラリを使用すると、これらの処理を簡単に実装できます。
まとめ
本記事では、シンプルなネットワーク画像ライブラリを自作しました。コード量も50行程度で実装することができましたが、キャッシュ管理や様々なフォーマットや状態管理等を考慮すると、既存の画像ライブラリ(Coilなど)を利用する方がメリットが大きいことが分かります。
本記事を通して画像ライブラリがどのような処理を行っているのか理解が深まれば幸いです