with で Android エンジニアをしている @t2low です。
かなり前の話です。
自分ではカッコいい感じのコードが書けたと思ったのですが、その後活用されずに眠っているので供養のつもりで記事にします。
(※ 実際のコードとは異なる部分があります)
コードを書いたきっかけ
ある画面で API から返された画像データ(URL)があれば読み込んで表示し、なければアプリ内の画像(drawable)を表示するという処理が必要になりました。
愚直に書くと次のようなコードになるかと思います。
(※ fun ImageView.loadImage(url: URL)
という URL を渡すと画像を読み込む ImageView の拡張関数が生えてると思ってください)
if (iconUrl != null)
iconImageView.loadImage(iconUrl)
else
iconImageView.setImageResource(R.drawable.something)
この画像データの種類に応じて処理を分けなければいけない、というのがめんどうですよね?めんどうに決まっています。
そこでどのような種類のデータでも渡すことができる仕組みを考えました。
画像クラス
まずは画像データを表す Image
クラスを作りました。
そもそも ImageView
に int
(Drawable の リソース ID) を渡したり、 URL
を渡すのが間違いの元です。ナンセンスです。
やはり ImageView
には Image
を渡さなければいけません。
なぜなら ImageView
は、Image
の View
だからです。
次のようなクラスを考えました。
sealed class Image {
object NoData: Image()
data class Resource(@DrawableRes resourceId: Int): Image()
data class Url(url: URL): Image()
}
みんな大好き sealed class
です。好きですよね?
(sealed interface
も大好きだと思いますが、当時はまだありませんでした)
使用例
これでデータの種類が異なっても同じ Image クラスとして表すことができるようになりました。
val iconImage: Image =
if (iconUrl != null) Image.Url(iconUrl)
else Image.Resource(R.drawable.no_image)
かんぺきです(ドヤァ)
ImageView に画像を設定するための拡張関数
Image クラスができたので、今度はそれを ImageView に設定するためのコードを書きましょう。
次のような拡張関数を作りました。
fun ImageView.setImage(image: Image) {
when (image) {
is Image.NoData -> this.setImageDrawable(null)
is Image.Resource -> this.setImageResource(image.resourceId)
is Image.Url -> this.loadImage(image.url)
}
}
みんな大好き拡張関数です。好きですよね?
やってることは単純に when
で分岐させてそれぞれ処理しているだけです。
分岐していた処理を隠蔽することに成功したと言えるでしょう(ドヤァ)
使用例
画像データの種類によって処理を変える必要がなくなりました。
どの種類の画像データでも、次のコードで画像を設定することができます。
val iconImage =
if (iconUrl != null) Image.Url(iconUrl)
else Image.Resource(R.drawable.no_image)
iconImageView.setImage(iconImage)
えー、すごーい、かっこいー。
供養
いい感じに書けたなー、と思ってはいるんですが、実際にはほとんど使われていません。
使われないコードということは、結局のところ大したコードではないのかもしれません。
ぶっちゃけ「 URL がなければ、 Drawable を表示する」というシチュエーションがほとんどありません。
大抵は URL が null になることなどなく、 ImageView.loadImage(URL)
だけで済んでしまいます。
解決したかった問題が小さかったんですね。
安らかに眠っていてください(技術的負債にはなりませんように)。
最後に
大したことないコードを紹介しましたが、自分はこれをとても楽しく書いていたことを覚えています。
ドヤっていたと思います。今でも愛着のあるコードです。
上では冗談めかして書きましたが、 sealed class や、拡張関数など、 Kotlin には書いていて楽しい仕様が盛りだくさんです。
Kotlin でコードを書いていると、なぜか厨二心(ちゅうにごころ)をくすぐられます。
infix
関数とかどうにかして使いたいですよね。
無駄に読みにくくカッコだけはいいコードを書かないように必死に抑えている毎日です。
Kotlin な方も、 Kotlin ではない方も、皆さん楽しくプログラミングしましょう~
楽しいプログラミングライフを!