Skip to content

Minimal add-on library which provides a nicer API for Preferences Datastore

License

Notifications You must be signed in to change notification settings

quebin31/preferences-helper

Repository files navigation

Preferences Helper

Minimal add-on library that provides a nicer API for Preferences DataStore which is more readable and convenient. I tend to write this same wrapper in all my projects and I've got tired of doing it manually so I decided to make it a library in case anyone else finds it useful.

Getting started

Just include the following dependency in your Gradle script, no need to add any extra repository if you're already using the Maven Central repository (which in most cases you'll be using):

implementation("com.quebin31:preferences-helper:1.0.0")

For a comprehensive list of examples head to the Guide.

Increment counter example

In order to see the benefits of using this library let's compare it to Preferences DataStore, as per the official Preferences DataStore documentation you'd write the following to update a value:

val Context.dataStore by preferencesDatastore(name = "datastore") // top file declaration

suspend fun incrementCounter() {
    val keyCounter = intPreferencesKey(name = "counter")
    context.dataStore.edit { mutablePreferences ->
        val currentValue = mutablePreferences[keyCounter] ?: 0
        mutablePreferences[keyCounter] = currentValue + 1
    }
}

That's a lot of boilerplate just to update a value, compare it to what you'd write if you were using this library:

val Context.dataStore by preferencesDatastore(name = "datastore") // top file declaration

// Somewhere you have access to the context, perhaps in a `PreferencesManager` that can be injected
// with Hilt
val helper = PreferencesHelper(context.dataStore) 

suspend fun incrementCounter() {
    val keyCounter = intPreferencesKey(name = "counter")
    helper.update(keyCounter, default = 0) { it + 1 }
}

Performance

By calling PreferencesHelper(datastore) we're just creating a thin wrapper around our preferences datastore, all calls are transformed to the operations you'd normally do if you were using the edit function directly, though there's an important catch, each function declared in the PreferencesHelper interface is atomic and separated from the others, you don't have to commit your changes, this has the advantage of providing an easy way to update, save, read or delete a value in very few lines.

However, the disadvantage is that doing multiple separate atomic operations is too expensive, each time a value in the internal data is updated the whole preferences map is updated, the solution to this is using the batch operation whenever you want to update multiple values at once in a single place, this is pretty similar to using edit but with the benefit of having scoped operations identical to the ones found in the PreferencesHelper interface:

Example

Instead of doing this 3 separate atomic operations:

helper.save(keyA, 3)
helper.delete(keyB)
helper.update(keyC, default = 0) { it + 1 }

You can use batch to reduce the number of atomic operations from 3 to 1:

helper.batch { // single transaction
    save(keyA, 3)
    delete(keyB)
    update(keyC, default = 0) { it + 1 }
}

LICENSE

This crate is licensed under the terms of the MIT License.

See LICENSE to see the full text.