Kotlin way to store and retrieve SharedPreferences
in Android
The approach of this library is to provide access to SharedPreferences
through class with delegated properties and
allows you to interact with your preferences just like with regular Kotlin properties:
class MyPreferences(context: Context) : Preferences(context, "MyPreferences") {
var myInt by Preference("myInt", 0)
var myString by Preference("myString", "default")
}
fun foo(context: Context) {
val preferences = MyPreferences(context)
preferences.myInt = 50 // Saved to SharedPreferences with apply()
val string = preferences.myString // "default" returned since there is no value provided yet
}
In case there is need for abstraction, you can always hide your preferences behind interface:
interface MyPreferences {
var myInt: Int
var myString: String
}
class MyPreferencesImpl(context: Context) : Preferences(context, "MyPreferences"), MyPreferences {
override var myInt by Preference("myInt", 0)
override var myString by Preference("myString", "default")
}
In some cases, you need to explicitly commit changes to the SharedPreferences
in a blocking manner.
By default, jotaro
saves all the preferences via SharedPreferences.Editor.apply()
when a preference property is
being set.
However, there is an option to alternate such behaviour and opt to the blocking SharedPreferences.Editor.commit()
call.
To do this, you need to provide isApplyOnSet
flag value as false
. This property is located in Preferences
and GsonPreferences
container classes, as well as Preference
delegate.
The difference between the two is only the level at which you're opting to commit()
.
- If you set this flag as false on a container class level, then all internal preferences will be committed.
- If you set this flag as false on a single preference, only this preference will be committed.
class MyPreferences(context: Context) : Preferences(context, "MyPreferences", isApplyOnSet = false) { // All preferences will be committed
var myInt by Preference("myInt", 0)
var myString by Preference("myString", "default")
}
class MyOtherPreferences(context: Context) : Preferences(context, "MyPreferences") {
var myInt by Preference("myInt", 0)
var myString by Preference("myString", "default", isApplyOnSet = false) // Only this preference will be committed
}
If you need to acquire your preferences in asynchronous way, library provides 2 extension functions to
provide lazy-initialized Deferred<T>
tasks:
val preferences = MyPreferences(context)
fun deferredInsideScope() {
MainScope().launch {
val text = asDeferred(preferences::myString).await()
myTextView.text = text
}
}
fun deferredOutsideScope(scope: CoroutineScope) {
val deferred = preferences::myString.asDeferred(scope)
MainScope().launch {
val text = deferred.await()
myTextView.text = text
}
}
By default, library supports all types that SharedPreferences
support out of the box:
- Int
- Long
- Float
- Boolean
- String
- Set (it will treat any Set<*> as Set due to the type erasure)
But if you need to store some custom objects in the preferences, library has you covered:
data class User(val id: Int, val name: String)
class MyPreferences(context: Context) : Preferences(context, "MyPreferences") {
var user by Preference(
"user",
User(0, ""),
serializer = { user -> "${user.id}|${user.name}" },
deserializer = { string -> string.split('|').let { User(it[0].toInt(), it[1]) } }
)
}
serializer
and deserializer
arguments are being invoked when the type of the preference is not supported
out of the box. You can write manual serialization, use jotaro-gson
artifact, or use any third party libraries, such as Jackson
.
Library provides separate artifact that extends default jotaro
artifact and provides GsonPreferences
class with
embedded serialization/deserialization through Gson
library. This class has additional constructor argument and
do not provide custom serializer
and deserializer
argument for the preference property delegate:
data class User(val id: Int, val name: String)
class MyGsonPreferences(gson: Gson, context: Context) : GsonPreferences(gson, context, "MyGsonPreferences") {
var user by Preference("user", User(0, ""))
}
Maven
<dependency>
<groupId>com.unlimity.jotaro</groupId>
<artifactId>jotaro</artifactId>
<version>LATEST_VERSION</version>
<type>pom</type>
</dependency>
<!-- With embedded Gson !-->
<dependency>
<groupId>com.unlimity.jotaro</groupId>
<artifactId>jotaro-gson</artifactId>
<version>LATEST_VERSION</version>
<type>pom</type>
</dependency>
or Gradle:
repositories {
jcenter()
}
dependencies {
implementation 'com.unlimity.jotaro:jotaro:LATEST_VERSION'
// With embedded Gson
implementation 'com.unlimity.jotaro:jotaro-gson:LATEST_VERSION'
}
Jotaro is available under the Apache License, Version 2.0.