LoginSignup
7
0

More than 3 years have passed since last update.

SharedPreferenceをDelegatedPropertiesでスリムに[Google I/O Android Appより]

Last updated at Posted at 2019-12-21

本記事はand factory Advent Calendar 2019 21日目の記事です!

こんにちは。Androidエンジニアの@nabetaro_jpです。The Google I/O 2019 Android AppのDataをLocalに保存するレイヤーのコードからSharedPreferencesに値を保存する部分で参考になる部分のメモとしてコードの内容を、簡略化してまとめたいと思います。

PreferenceStorage

Preferenceに保存する値のメンバーを定義するインターフェース

PreferenceStorage.kt

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

Preference.kt
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

SharedPreferenceStorage.kt

@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で行うよ〜 ってことですね。

参考:https://sys1yagi.gitbooks.io/anatomy-kotlin/content/%E3%83%87%E3%83%AA%E3%82%B2%E3%83%BC%E3%83%88%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E6%AD%A3%E4%BD%93.html

終わり

ボイラープレートも減ってスッキリとprefに保存する処理がかけることでしょう。 Kotlinに感謝ですね〜👀

7
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
7
0