Skip to content

Instantly share code, notes, and snippets.

@orwir
Last active March 12, 2024 09:27
Show Gist options
  • Save orwir/3df30b3ffe830a22bb1d173f08674936 to your computer and use it in GitHub Desktop.
Save orwir/3df30b3ffe830a22bb1d173f08674936 to your computer and use it in GitHub Desktop.
Kotlin extensions for shared preferences
import android.content.Context
import android.content.SharedPreferences
import kotlin.reflect.KProperty
/**
* Creates delegate for property from [prefs] with the key presented as className+propertyName.
* @param T type of the property
* @param defaultValue is used if property not set
* @return wrapper for property accessors
*/
inline fun <reified T> sharedPref(prefs: SharedPreferences, defaultValue: T = defaultForType()) =
object : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>) = prefs[getKey(thisRef, property), defaultValue]
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
prefs[getKey(thisRef, property)] = value
}
private fun getKey(thisRef: Any, property: KProperty<*>) = "${thisRef.javaClass.simpleName}.${property.name}"
}
/**
* Set property [value] to shared preferences by [key].
* @param T type of the property
*/
inline operator fun <reified T> SharedPreferences.set(key: String, value: T) {
edit().apply {
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
is Long -> putLong(key, value)
else -> throw UnsupportedOperationException("Type ${T::class} is not supported yet")
}
}.apply()
}
/**
* Get property value by [key]. If property not set return [defaultValue] ("", true, 0 if not given).
* @param T type of the property
* @return saved value or [defaultValue].
*/
inline operator fun <reified T> SharedPreferences.get(key: String, defaultValue: T = defaultForType()) =
when (defaultValue) {
is String -> getString(key, defaultValue) as T
is Int -> getInt(key, defaultValue) as T
is Boolean -> getBoolean(key, defaultValue) as T
is Float -> getFloat(key, defaultValue) as T
is Long -> getLong(key, defaultValue) as T
else -> throw UnsupportedOperationException("Type ${T::class} is not supported yet")
}
/**
* Default value for typical property types.
* @param T [String] -> empty string
* @param T [Int] / [Float] / [Long] -> 0
* @param T [Boolean] -> false
*/
inline fun <reified T> defaultForType(): T =
when (T::class) {
String::class -> "" as T
Int::class -> 0 as T
Boolean::class -> false as T
Float::class -> 0F as T
Long::class -> 0L as T
else -> throw IllegalArgumentException("Default value not found for type ${T::class}")
}
//--------------- Use case ------------
class PreferencesRepository(context: Context) {
private val prefs = context.getSharedPreferences("my_preferences", Context.MODE_PRIVATE)
var boolPref = sharedPref<Boolean>(prefs)
var intPref = sharedPref(prefs, 42)
val longPref = sharedPref<Long>(prefs)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment