12
10

More than 1 year has passed since last update.

Android enumではなくIntDefを使ってdata classを組み立てる

Last updated at Posted at 2021-10-05

環境

Android Studio Arctic Fox | 2020.3.1 Patch 2
Kotlin 1.5.31

概要

列挙型の値を使うときに、@IntDefを生かしてdata classを組み立ててみます。

なぜenumではなくIntDefを使うのか

Google I/O 19で、Build apps for the next billion users という動画があります。

この中の、Reduce your app sizeに挙げている項目で、Avoid enumerationsというものがあります。
一個のenumでファイルのサイズが 1.0~1.4 KB程度増えるとあり、使い方によってはさらに増えるそうです。
このことは、公式のドキュメントにも記載があります。
https://developer.android.com/topic/performance/reduce-apk-size#remove-enums

というわけで、Google wayとしてenumを使わずにIntDefアノテーションで対応をしてみます。

TypedefアノテーションクラスをJavaで用意する

IntDefを定義するアノテーションクラスをJavaで用意します。

@IntDef({Status.IDLE, Status.PROCESSING, Status.DONE, Status.CANCELLED})
@Retention(RetentionPolicy.SOURCE)
@interface Status {
    int IDLE = 0;
    int PROCESSING = 1;
    int DONE = 2;
    int CANCELLED = 3;
}

Kotlinで用意しようとすると、後述のアノテーションによる検査が効かなかったです。これではアノテーションの意味がないのでJavaで用意してますが、反映させる方法があったら誰か教えてください。

2022/10/23追記
以下の環境ではKotlinでもアノテーション検査が効いていることを確認しています。

Android Studio Dolphin | 2021.3.1
Build #AI-213.7172.25.2113.9014738, built on September 1, 2022
Runtime version: 11.0.13+0-b1751.21-8125866 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 12.6
GC: G1 Young Generation, G1 Old Generation
Memory: 2048M
Cores: 16
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false

Non-Bundled Plugins:
    org.intellij.plugins.markdown (213.6777.22)
    com.github.setial (4.0.2)
    Dart (213.7433)
    com.thoughtworks.gauge (213.5744.125)
    de.ohmesoftware.parcelablegenerator (0.7.1)
    io.flutter (70.2.3)

// アノテーションによる検査が効かない
@Retention(AnnotationRetention.SOURCE)
@IntDef(IDLE, PROCESSING, DONE, CANCELLED)
annotation class Status

// Declare the constants
const val IDLE = 0
const val PROCESSING = 1
const val DONE = 2
const val CANCELLED = 3

data classでIntDefな値を提供する

以下のコードのように、コンストラクタの引数には@setparam をつけたprivate varなパラメータを用意し、別途@getで公開用のvalなパラメータを用意します。

data class MyData(@setparam:Status private var _state: Int) {
    @get:Status
    val state: Int = _state
}

IntDefな値を提供するdata classを使う

全体のコード

        val data = MyData(CANCELLED)
        val state = data.state
        val i = when(state) {
            Status.CANCELLED -> {
                1
            }
            Status.DONE -> {
                2
            }
            Status.IDLE -> {
                3
            }
            Status.PROCESSING -> {
                4
            }
            else -> 5
        }
        print(i)

アノテーションクラスをJavaで提供していると、data classの@getの効果で、画像のようにIntDefの定数を補完するための項目が出てきます。これを使うことでenumと同じ処理分岐が可能になります。
スクリーンショット 2021-10-06 0.24.59.png

同様に、@setparamの効果で、data classのコンストラクタに適当な数値を入れると補完候補に@IntDefで定義した値が選択できます。
スクリーンショット 2021-10-06 0.27.58.png

まとめ

enumのほうが作りやすい
つかおう!IntDef!

12
10
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
12
10