以下の方法では動きません
以下で記載されている方法では動作しません。
すみません。
どんな記事?
RealmのフィールドにはEnumなどの型サポートがないので、
特定の値しか入らないようなフィールドを自作した。
そんで、Kotlinを使うとここまで楽になったよという話。
今回は分かりやすくするために普通のRDBと同じ用語を使います。
Enumでsafetyにしたい
例えば PERSONというテーブルにPEREFCTUREという都道府県が入るカラムがあるとします。
当然ここには、存在する都道府県以外の名称は入ってほしくないですよね。
特定の値しか許容しない仕組みといえば、列挙型(Enum)ですが、
RealmではEnum型のフィールドはサポートしていないようです。
じゃあ、自作してしまおう。
早速コード
enum class PrefectureEnum(val value: String) {
TOKYO("東京都"),
KANAGAWA("神奈川県"),
// .....以下47都道府県
}
class Person(
/** 名前 */
@Required @PrimaryKey open var name: String = "",
/** 都道府県 */
prefecture: String = ""
companion object {
// 値が含まれているかをチェックする
@JvmStatic fun contains(value: String): Boolean {
return values().map { it.value }.contains(value)
}
}
) : RealmObject() {
open var prefecture: String = ""
//カスタムゲッターでEnum以外の値は取得できないようにする
get() = if (PrefectureEnum.contains(field) field else "あなたどこ出身?"
//カスタムセッターでEnum以外の値はセットできないようにする
set(value) {
if (PrefectureEnum.contains(value)) field = value
else field = "あなたどこ出身?"
}
init {
this.prefecture = prefecture
}
}
Enumクラスに独自のcontainsメソッドを定義
Enum.valuesだとEnum型の配列として取得されるので、mapで値の配列に変換してから
containsで値が含まれているかのチェックを行うようにしました。
Streamが手軽に使えるのはKotlinの大きな強みっすね。
Personクラスにカスタムセッターゲッターを定義
特定のフィールドにEnumを適応したい場合には
カスタムセッターとゲッターを指定するのがポイント。
Enumクラスで定義した値が含まれていなかったときには、それ専用の値を入れてます。
注意点はcontainsの引数や戻り値には直接のプロパティを渡してはいけないところ。
プロパティ自体を渡すと自分のgetter/setterが再び呼ばれるのでスタックオーバーフローで死にます。
必ず、値だけを渡すようにfieldを指定してください。
Kotlinサイコーかよ
Kotlinのカスタムゲッター、セッターが存分に活かされたとこです。
StreamもAndroidでJava8が対応したとはいえ、まだ一部機能は制限されてますからね。
というわけでKotlinはやっぱ良い。