Use DataStore instead of Shared Preferences

·

3 min read

Introduction

You may come across a requirement in your app to store some configuration (not that big to use Room).

For example, the previous UI mode - (Dark/Light)

You might come across Shared Preferences for this requirement. Shared Preferences are used to persist data of key-value pairs.

I agree that shared preferences work fine but are still way too old. Imagine if you want to observe the live changes of a preference value. you can't.

DataStore

DataStore is a part of Jetpack libraries that lets you store data of key-value pairs or typed objects in the device.

Types

  • Preferences DataStore - Stores key-value pairs

  • Proto DataStore - Stores typed objects using protocol buffers.

In this guide, we will learn about the Preferences DataStore.

Proto DataStore is for another day.

Why you should use DataStore instead of Shared Preferences?

SharedPreferences

Guide

Setup

Add the datastore preference in your grade dependency

dependencies {
        implementation "androidx.datastore:datastore:1.0.0"
}

Build DataStore

Create a preference data store as an extension of context using the preferencesDataStore delegate in the top level of a Kotlin file.

The name of the Preferences DataStore is a mandatory parameter.

This ensures that a single instance of DataStore is created for the application process.

// Top level of any kotlin file.
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "configs")

Create Preference Keys

To store key-value pairs, we have to create keys for the preferences.

object PreferenceKeys {
    val booleanKey = booleanPreferencesKey(name = "key_for_bool_value")
    val byteArrayKey = byteArrayPreferencesKey(name = "key_for_byte_array_value")
    val doubleKey = doublePreferencesKey(name = "key_for_double_value")
    val floatKey = floatPreferencesKey(name = "key_for_float_value")
    val intKey = intPreferencesKey(name = "key_for_int_value")
    val longKey = longPreferencesKey(name = "key_for_long_value")
    val stringKey = stringPreferencesKey(name = "key_for_string_value")
    val stringSetKey = stringSetPreferencesKey("key_for_string_set_value")
}

Write data

Write a value to the preferences with the following code.

suspend fun writeValue(key: Preferences.Key<Int>, value: Int) {
    context.dataStore.edit { preferences ->
        // Set the new value to the preference.
        preferences[key] = value
    }
}

Write a value from a fragment or activity

// In an activity or fragment
// You can use any CoroutineScope other than lifeCycleScope.
lifeCycleScope.launch {
    writeValue(key = intKey, value = 17)
}

Read data

Read value from the preferences with the following code.

It returns a Flow.

fun readValue(key: Preferences.Key<Int>, defaultValue: Int): Flow<Int> {
    return context.dataStore.data.map { preferences ->
        preferences[key] ?: defValue
    }
}

Collect the value from the Flow

// In an activity or fragment
// You can use any CoroutineScope other than lifeCycleScope.
lifeCycleScope.launch {
    readValue(key = intKey, defaultValue = 0).collect { value ->
        // Utilize the value here
    }
}

Bonus

Extension function to work with all types of keys.

/***
 *
 * An Extension function to DataStore<Preference>.
 * Generic way to getting preference value from the data store.
 * Returns preference value for the @param key if found,
 * Otherwise it returns @param defValue
 *
 * @param key Preference key
 * @param defValue default value if the preference key is not found
 *
 * @return a Flow of type T
 */
fun <T> DataStore<Preferences>.getValue(
    key: Preferences.Key<T>,
    defValue: T
): Flow<T> {
    return data.map { preferences ->
        preferences[key] ?: defValue
    }
}

/***
 *
 * An Extension function to DataStore<Preference>
 * Generic way to editing preference value from the data store.
 * Edit the value of the preference @param key with @param value.
 *
 * @param key Preference key
 * @param value Value need to be set to the given key
 *
 */
suspend fun <T> DataStore<Preferences>.setValue(
    key: Preferences.Key<T>,
    value: T
) {
    edit { preferences ->
        preferences[key] = value
    }
}

That's it for today.


Please do like if it helped you.

Comment if you have any queries.

Share if you want to help others.

For more articles like this, Do follow.

Thanks for reading. <3

Did you find this article valuable?

Support Dhina17 by becoming a sponsor. Any amount is appreciated!