3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

withAdvent Calendar 2021

Day 13

ImageView に画像データをいい感じに渡すカッコいいコード

Last updated at Posted at 2021-12-13

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 クラスを作りました。
そもそも ImageViewint (Drawable の リソース ID) を渡したり、 URL を渡すのが間違いの元です。ナンセンスです。
やはり ImageView には Image を渡さなければいけません。
なぜなら ImageView は、ImageView だからです。

次のようなクラスを考えました。

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 ではない方も、皆さん楽しくプログラミングしましょう~
楽しいプログラミングライフを! :wave:

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?