Kotlin Data Storage is a multiplatform coroutine-based kotlin library for storing Serializables with kotlinx.serialization and delegates.
If you need to store any kind of preferences in your app, you would probably use this framework since it has a common API for any platform you need.
Expand
import ProgramData.userName
object ProgramData : KFileDataStorage() {
val userName by property<String>() // shortcut for property<String?> { null }
}
fun main() {
if(userName == null) {
println("Hi dear user, how should I call you?")
userName = readLine() ?: "Anonymous"
println("Okay ${userName}, see you")
} else {
println("Glad to see you again, $userName")
}
}
Expand
object CookiesStorage : KLocalDataStorage() {
val uniqueADId by property { Random.nextLong() }
}
fun main() {
console.log("🙈 I'm tracking you, ${CookiesStorage.uniqueADId}!")
}
Expand
// Initialize context first:
class App : Application() {
override fun onCreate() {
super.onCreate()
KDS.onCreate(app = this)
}
}
...
object SharedStorage : KSharedDataStorage() {
var clicks by int { 0 }
}
...
import SharedStorage.clicks
class MainActivity : Activity() {
override fun onCreate(bundle: Bundle?) {
...
main.setOnClickListener {
updateClicks(++clicks)
}
}
}
Expand
You can also store android app state with the library
class MainActivity : Activity() {
private val state = object : KBundleDataStorage() {
var score by int { 0 } // This will be automatically saved and restored
}
override fun onCreate(bundle: Bundle?) = state.fillState(bundle) {
super.onCreate(bundle)
}
// OR
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
state.restoreInstanceState(bundle)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
state.saveInstanceState(outState)
}
}
Custom
property
are also allowed there made with serialization to string followed bybundle.putString
Expand
There is also an API to use mutable objects
data class Item (
var foo: Foo? = null
)
object MainStorage : ... {
val item by property(::Item)
}
// Launches an asynchronous commit after block()
fun editItem() = MainStorage.mutate {
item.foo = ...
}
// Suspends until commit
suspend fun editItem() = MainStorage.mutateCommit {
item.foo = ...
}
// Blocking mutation
fun editItem() = MainStorage.mutateBlocking {
item.foo = ...
}
suspend fun main() {
// Launches a commit and cancels the previous one
MainStorage.launchCommit()
// Suspends until commit
MainStorage.commit()
// Blocking commit
MainStorage.commitBlocking()
}
Expand
There are some (experimental for now) entities which may automatically perform save operation on mutate:
object MainStorage : ... {
val list by storageList<Boolean>()
val map by storageMap<String, Int>()
val set by storageSet { mutableSetOf(1, 2, 3) }
}
fun main() {
// Then any mutation on this entities will perform save
// The saving operation will same as operation when assigning variable to new value
// It means that in KFileDataStorage async save will be invoked, while in KLocalDataStorage blocking `put` method
MainStorage.list += true
}
Note that the library is written in a way where you may fully customize it (add xml format for files/etc, implement java.Serializable support and so on, interfaces are common, so you may still use delegates, commits, mutations on it)
Library integrates with some other libraries providing convenient API for storing androidx MutableState
. Integrations still require including storage dependency.
Expand
Expand
object ComposeStorage : ... {
val username by mutableState<String>()
}
...
@Composable
fun UserNameText() {
val username by remember { ComposeStorage.username }
Text (
text = username
)
}
Expand
object AppData : KLocalDataStorage() {
val clicks by observableValue { 0 }
}
class App : Application() {
override fun start() {
root(id = "root") {
vPanel {
h1(AppData.clicks) { clicks ->
+ "Clicked $clicks times"
}
button(text = "Click!") {
onClick {
// Changes still handled by storage
clicks.value++
}
}
}
}
}
}
fun main() = startApplication(::App)
Expand
object CoroutinesStorage : ... {
// Use it everywhere you need to save state flow values
val stateFlow by mutableStateFlow<String>()
}
When targeting JS, only IR is supported
$version
- the library version, can be found in badge above
All kds
packages are located at repository maven.kotlingang.fun, so make sure you include one.
KDataStorage async/sync implementation with files.
Platforms:
Dependency: fun.kotlingang.kds:json-files:$version
KDataStorage sync implementation with browser
localStorage
Platforms:
Dependency: fun.kotlingang.kds:json-local-storage:$version
KDataStorage async implementation with android
SharedPreferences
Platforms:
Dependency: fun.kotlingang.kds:json-shared-preferences:$version
Example: GitHub repo
KDataStorage sync implementation with android
Bundle
Platforms:
Dependency: fun.kotlingang.kds:json-bundle:$version
Example: GitHub repo
MutableState implementation
Platforms:
Dependency: fun.kotlingang.kds:extensions-androidx:$version
MutableStateFlow implementation
Platform: Any
Dependency: fun.kotlingang.kds:extensions-coroutines:$version
ObservableState implementation
Platform:
Dependency: fun.kotlingang.kds:extensions-kvision:$version
If you want to create your own implementation, take a look at the following dependencies
The core module with delegates and main interfaces
Platforms: Any
Dependency: fun.kotlingang.kds:core:$version
The json module with abstraction over any storage uses json serialization (also proxies references to allow mutations)
Platforms: Any
Dependency: fun.kotlingang.kds:json:$version