こんばんは、Kotlin大好きAndroidアプリエンジニアの id:takuji31 です。
※これは はてなエンジニア Advent Calendar 2018 21日目の記事です。
provideDelegate operatorについて
provideDelegate operatorはKotlin 1.1からあるオペレーターで、プロパティーの移譲オブジェクトを生成することができます。
Delegated Properties - Kotlin Programming Language
このオペレーターを挟むことで、Delegated property生成時にロジックを実行することができ、例えば以下のようなことができます。
使い方
まずはプロパティーになるclassを定義しましょう。
読み書きできるプロパティーを作るには kotlin.properties.ReadWriteProperty
を実装したclassが必要です。
ここではAndroidのSharedPreferencesを操作するStringのpropertyを定義します。
class SharedPreferencesProperty(private val key: String, private val defaultValue: String?) : ReadWriteProperty<PreferencesModel, String?> { override fun getValue(thisRef: PreferencesModel, property: KProperty<*>): String? { return thisRef.sharedPreferences.getString(key, defaultValue) } override fun setValue(thisRef: PreferencesModel, property: KProperty<*>, value: String?) { thisRef.sharedPreferences.edit().putString(key, value).apply() } }
次に provideDelegate
をもつclassを定義します。
SharedPreferencesに値を出し入れするにはキーを保持する必要がありますが、必ずしもキーがプロパティー名と同じではありません。
そこでプロパティーの移譲オブジェクトにキーを渡せるようにします。
もちろんキーは空文字だと困るので検証したいですね。
class SharedPreferencesPropertyProvider( private val key: String? = null, private val defaultValue: String? = null ) { operator fun provideDelegate( thisRef: PreferencesModel, prop: KProperty<*> ): ReadWriteProperty<PreferencesModel, String?> { val propertyName = prop.name val key = key ?: propertyName require(key.isNotEmpty()) { "Key cannot be empty" } return SharedPreferencesProperty(key, defaultValue) } }
最後にこのプロパティーを使うclassを定義します。
open class PreferencesModel(context: Context, name: String) { internal val sharedPreferences: SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE) protected fun stringPreferences(key: String? = null, defaultValue: String? = null) = SharedPreferencesPropertyProvider(key, defaultValue) } class UserPreferences(context: Context) : PreferencesModel(context, "user") { var name: String? by stringPreferences() var profile: String? by stringPreferences("profile") }
あとはこの UserPreferences
のインスタンスのプロパティーをset/getするとSharedPreferencesを操作できます。
UserPreferences.profile
にはキーの値を渡していますが、例えばこの値を空文字にするとインスタンス生成時に例外が発生するようになります。
正しくインスタンス生成ができるかはテストでチェックしてやるとよいでしょう。
最後に
provideDelegate
メソッドを使うとDelegated propertyを更に柔軟にすることができるでしょう。
明日の担当は id:tkzwtks さんです。