Настало время поговорить о SharedPreferences. Как Kotlin может помочь сделать их использование более удобным и приятным? Первое, что приходит в голову, это кастомные геттер и сеттер:

internal val sharedPreferences: SharedPreferences = context.getSharedPreferences("MY_PREFS", Context.MODE_PRIVATE)

var spInt: Int
    get() = sharedPreferences.getInt("spInt", 0)
    set(value) = sharedPreferences.edit().putInt("spInt", value).apply()

Этот финт функционален, но недостаточно изящен. Давайте взлянем в сторону делегатов:

private operator fun SharedPreferences.setValue(spManager: SPManager, property: KProperty<*>, l: Long) {
    spManager.sharedPreferences.edit().putLong(property.name, l).apply()
}

private operator fun SharedPreferences.getValue(spManager: SPManager, property: KProperty<*>): Long {
    return spManager.sharedPreferences.getLong(property.name, 0)
}

Теперь мы можем объявлять переменные через этот делегат:

var spLong: Long by sharedPreferences

Но в таком подходе есть два неприятных момента: мы не можем влиять на значение по умолчанию, а имя ключа в SharedPreferences всегда будет таким же, как имя переменной. Пора подняться на уровень выше!

fun SharedPreferences.string(name: String, defValue: String? = null) = StringPrefs(name, defValue, this)

class StringPrefs(private val name: String, private val defValue: String?, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>): String? = prefs.getString(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, s: String?) = prefs.edit().putString(name, s).apply()
}

Вот как теперь можно объявлять переменные (параметр defValue можно опустить):

var spString: String? by sharedPreferences.string(name = "spString", defvalue = "none")

И последний апгрейд. Мы можем вынести все делегаты в отдельный файл и пользоваться таким способом по всему проекту:

fun SharedPreferences.boolean(name: String, defValue: Boolean = false) = BooleanPrefs(name, defValue, this)
fun SharedPreferences.float(name: String, defValue: Float = 0f) = FloatPrefs(name, defValue, this)
fun SharedPreferences.int(name: String, defValue: Int = 0) = IntPrefs(name, defValue, this)
fun SharedPreferences.long(name: String, defValue: Long = 0L) = LongPrefs(name, defValue, this)
fun SharedPreferences.string(name: String, defValue: String = "") = StringPrefs(name, defValue, this)
fun SharedPreferences.nullableString(name: String, defValue: String? = null) = NullableStringPrefs(name, defValue, this)

class BooleanPrefs(private val name: String, private val defValue: Boolean, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getBoolean(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, b: Boolean) = prefs.edit().putBoolean(name, b).apply()
}

class FloatPrefs(private val name: String, private val defValue: Float, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getFloat(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, f: Float) = prefs.edit().putFloat(name, f).apply()
}

class IntPrefs(private val name: String, private val defValue: Int, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getInt(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, i: Int) = prefs.edit().putInt(name, i).apply()
}

class LongPrefs(private val name: String, private val defValue: Long, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>) = prefs.getLong(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, l: Long) = prefs.edit().putLong(name, l).apply()
}

class StringPrefs(private val name: String, private val defValue: String, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>): String = prefs.getString(name, defValue) ?: defValue
    operator fun setValue(thisRef: Any, property: KProperty<*>, s: String) = prefs.edit().putString(name, s).apply()
}

class NullableStringPrefs(private val name: String, private val defValue: String?, private val prefs: SharedPreferences) {
    operator fun getValue(thisRef: Any, property: KProperty<*>): String? = prefs.getString(name, defValue)
    operator fun setValue(thisRef: Any, property: KProperty<*>, s: String?) = prefs.edit().putString(name, s).apply()
}

Использование:

var spString1: String by sharedPreferences.string(name = "spString1")
var spString2: String by sharedPreferences.string(name = "spString2", defValue = "def")
var spString3: String? by sharedPreferences.nullableString(name = "spString3", defValue = "def")
var spString4: String? by sharedPreferences.nullableString(name = "spString4", defValue = null)
var spBoolean: Boolean by sharedPreferences.boolean(name = "spBoolean")
var spFloat: Float by sharedPreferences.float(name = "spFloat", defValue = 1f)

 

Добавить комментарий

Закрыть меню