本記事はand factory Advent Calendar 2019 21日目の記事です!
こんにちは。Androidエンジニアの@nabetaro_jpです。The Google I/O 2019 Android AppのDataをLocalに保存するレイヤーのコードからSharedPreferencesに値を保存する部分で参考になる部分のメモとしてコードの内容を、簡略化してまとめたいと思います。
PreferenceStorage
Preferenceに保存する値のメンバーを定義するインターフェース
interface PreferenceStorage {
var id: Int
var name: String?
var isSubscribed: Boolean
}
ReadWritePropertyを継承したクラス:StringPreference, IntPreference, BooleanPreference
ReadWritePropertyとは読み取りや書き込みのプロパティのproperty delegatesを実装するのに使用できるインターフェースです。便宜上のみの提供なので、基本このインターフェースを拡張する必要はないのですが、データの永続化のために拡張している模様です。
interface ReadWriteProperty<in R, T>
参考:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-read-write-property/index.html
class BooleanPreference(
private val preferences: Lazy<SharedPreferences>,
private val name: String,
private val defaultValue: Boolean
) : ReadWriteProperty<Any, Boolean> {
@WorkerThread
override fun getValue(thisRef: Any, property: KProperty<*>): Boolean {
return preferences.value.getBoolean(name, defaultValue)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: Boolean) {
preferences.value.edit { putBoolean(name, value) }
}
}
class StringPreference(
private val preferences: Lazy<SharedPreferences>,
private val name: String,
private val defaultValue: String?
) : ReadWriteProperty<Any, String?> {
@WorkerThread
override fun getValue(thisRef: Any, property: KProperty<*>): String? {
return preferences.value.getString(name, defaultValue)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String?) {
preferences.value.edit { putString(name, value) }
}
}
class IntPreference(
private val preferences: Lazy<SharedPreferences>,
private val name: String,
private val defaultValue: Int = 0
) : ReadWriteProperty<Any, Int> {
@WorkerThread
override fun getValue(thisRef: Any, property: KProperty<*>): Int {
return preferences.value.getInt(name, defaultValue)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) {
preferences.value.edit { putInt(name, value) }
}
}
SharedPreferenceStorage : PreferenceStorage
@Singleton
class SharedPreferenceStorage @Inject constructor(context: Context) : PreferenceStorage {
private val prefs: Lazy<SharedPreferences> = lazy {
// Lazy to prevent IO access to main thread.
context.applicationContext.getSharedPreferences(
PREFS_NAME, MODE_PRIVATE
)
}
override var id: Int by IntPreference(prefs, PREF_ID)
override var name: String? by StringPreference(prefs, PREF_NAME, "")
override var isSubscribed: Boolean by BooleanPreference(prefs, PREF_IS_SUBSCRIBED, false)
companion object {
const val PREFS_NAME = "my_preference"
const val PREF_ID = "pref_id"
const val PREF_NAME = "pref_name"
const val PREF_IS_SUBSCRIBED = "pref_is_subscribed"
}
}
注目したのはここ👀
override var name: String? by StringPreference(prefs, PREF_NAME, "")
DelegatedProperties
(委譲プロパティ)ですね。by
を記載することで nameへの読み書き、つまりGetter/Setterの処理を byで指定している StringPreferenceで行うよ〜 ってことですね。
終わり
ボイラープレートも減ってスッキリとprefに保存する処理がかけることでしょう。 Kotlinに感謝ですね〜👀