Skip to content

Instantly share code, notes, and snippets.

@LouisCAD
Last active September 14, 2020 17:12
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save LouisCAD/1231ea975e14571ac2b3c6ceeeabf962 to your computer and use it in GitHub Desktop.
Save LouisCAD/1231ea975e14571ac2b3c6ceeeabf962 to your computer and use it in GitHub Desktop.
Make Android's SharedPreferences as simple as a field in kotlin.
package com.mypackage.myapp.prefs
import android.content.Context
import com.mypackage.myapp.appCtx
object MyPreferences : Preferences(name = "MyPrefsFileName") {
var userWantsFancyUi by BoolPref(Keys.FANCY_UI, false)
var isFcmTokenSent by BoolPref(Keys.FCM_TOKEN_SENT_TO_SERVER, false)
var eggTapsCount by LongPref(Keys.EGG_TAPS_COUNT, 0L)
object Keys {
const val FANCY_UI = "fancyUI"
const val FCM_TOKEN_SENT_TO_SERVER = "fcmTokenSent"
const val EGG_TAPS_COUNT = "eggTapsCount"
}
}
package com.mypackage.myapp.prefs
import android.content.Context
import android.content.SharedPreferences
import com.google.android.agera.BaseObservable
import com.google.android.agera.Observable
import com.google.android.agera.Updatable
import com.mypackage.myapp.appCtx
abstract class ObservablePreferences(ctx: Context = appCtx, name: String) : Preferences(ctx, name), Observable {
private val changeListener by lazy { ChangesObservable() }
/**
* Updated before the update is dispatched. The value should be only used to check which
* preference changed.
*/
var lastChangedKey = ""
private set
override fun addUpdatable(updatable: Updatable) = changeListener.addUpdatable(updatable)
override fun removeUpdatable(updatable: Updatable) = changeListener.removeUpdatable(updatable)
inner private class ChangesObservable : BaseObservable(), SharedPreferences.OnSharedPreferenceChangeListener {
override fun observableActivated() = prefs.registerOnSharedPreferenceChangeListener(this)
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
check(sharedPreferences in this@ObservablePreferences)
lastChangedKey = key
dispatchUpdate()
}
override fun observableDeactivated() = prefs.unregisterOnSharedPreferenceChangeListener(this)
}
}
package com.mypackage.myapp.prefs
import android.content.Context
import com.mypackage.myapp.appCtx
abstract class Preferences(ctx: Context = appCtx, name: String) {
private val prefs = ctx.getSharedPreferences(name, Context.MODE_PRIVATE)
operator fun contains(o: Any) = prefs === o
internal inner class BoolPref(key: String, defaultValue: Boolean)
: BoolPrefField(prefs, key, defaultValue)
internal inner class IntPref(key: String, defaultValue: Int)
: IntPrefField(prefs, key, defaultValue)
internal inner class FloatPref(key: String, defaultValue: Float)
: FloatPrefField(prefs, key, defaultValue)
internal inner class LongPref(key: String, defaultValue: Long)
: LongPrefField(prefs, key, defaultValue)
internal inner class StringPref(key: String, defaultValue: String)
: StringPrefField(prefs, key, defaultValue)
}
package com.mypackage.myapp.prefs
@file:Suppress("NOTHING_TO_INLINE")
import android.content.SharedPreferences
import kotlin.reflect.KProperty
internal abstract class BoolPrefField(private val prefs: SharedPreferences,
private val key: String,
defaultValue: Boolean) {
private var cachedValue = prefs.getBoolean(key, defaultValue)
inline operator fun getValue(thisRef: Any?, prop: KProperty<*>) = cachedValue
inline operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Boolean) {
cachedValue = value
prefs.edit().putBoolean(key, value).apply()
}
}
internal abstract class IntPrefField(private val prefs: SharedPreferences,
private val key: String,
defaultValue: Int) {
private var cachedValue = prefs.getInt(key, defaultValue)
inline operator fun getValue(thisRef: Any?, prop: KProperty<*>) = cachedValue
inline operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Int) {
cachedValue = value
prefs.edit().putInt(key, value).apply()
}
}
internal abstract class LongPrefField(private val prefs: SharedPreferences,
private val key: String,
defaultValue: Long) {
private var cachedValue = prefs.getLong(key, defaultValue)
inline operator fun getValue(thisRef: Any?, prop: KProperty<*>) = cachedValue
inline operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Long) {
cachedValue = value
prefs.edit().putLong(key, value).apply()
}
}
internal abstract class FloatPrefField(private val prefs: SharedPreferences,
private val key: String,
defaultValue: Float) {
private var cachedValue = prefs.getFloat(key, defaultValue)
inline operator fun getValue(thisRef: Any?, prop: KProperty<*>) = cachedValue
inline operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Float) {
cachedValue = value
prefs.edit().putFloat(key, value).apply()
}
}
internal abstract class StringPrefField(private val prefs: SharedPreferences,
private val key: String,
defaultValue: String) {
private var cachedValue = prefs.getString(key, defaultValue)!!
inline operator fun getValue(thisRef: Any?, prop: KProperty<*>) = cachedValue
inline operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
cachedValue = value
prefs.edit().putString(key, value).apply()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment