DataStore is a modern data storage solution introduced by Google that comes as a replacement for SharedPreferences in Android. While SharedPreferences is a way to store key-value pairs, DataStore is more robust and offers more flexibility, such as type-safety and asynchronous operations using Kotlin coroutines.
There are two types of DataStore:
SharedPreferences).Here, I'll show you how to use the Preferences DataStore:
Add the required dependencies to your build.gradle:
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha01"
Ensure you have the latest version.
You can create an instance of DataStore using the Context:
val dataStore: DataStore<Preferences> = context.createDataStore( name = "settings" )
Reading from the DataStore is asynchronous:
val EXAMPLE_KEY = preferencesKey<String>("example_key") val exampleFlow: Flow<String?> = dataStore.data .map { preferences -> // Return the value or null if not set preferences[EXAMPLE_KEY] } To observe this data in a UI, you can collect it:
lifecycleScope.launch { exampleFlow.collect { value -> // Use the value } } Writing to DataStore is also asynchronous:
suspend fun saveString(key: Preferences.Key<String>, value: String) { dataStore.edit { preferences -> preferences[key] = value } } You'd call this function from a coroutine:
lifecycleScope.launch { saveString(EXAMPLE_KEY, "This is an example") } DataStore also provides utilities to migrate from SharedPreferences:
val dataStore: DataStore<Preferences> = context.createDataStore( name = "settings", migrations = listOf( SharedPreferencesMigration(context, "legacy_preferences_name") ) )
SharedPreferences.Remember, as with any new library, always refer to the official documentation to understand the full capabilities and best practices.
Preferences DataStore example code Android:
// Create a DataStore instance val dataStore: DataStore<Preferences> = context.createDataStore(name = "settings") // Write data to DataStore dataStore.edit { preferences -> preferences[KEY_NAME] = "John Doe" preferences[KEY_AGE] = 25 } // Read data from DataStore val nameFlow: Flow<String?> = dataStore.data.map { preferences -> preferences[KEY_NAME] ?: "" } // Observe changes in data nameFlow.collect { name -> Log.d(TAG, "Name: $name") } Migrating from SharedPreferences to DataStore in Android:
Update your code by replacing SharedPreferences with DataStore. Use the edit function to write data and observe changes using Flow.
Working with key-value pairs in Preferences DataStore:
Use key-value pairs for storing and retrieving data:
// Write data dataStore.edit { preferences -> preferences[KEY_USER_ID] = "123" } // Read data val userId: Flow<String?> = dataStore.data.map { preferences -> preferences[KEY_USER_ID] ?: "" } Custom data types in Preferences DataStore Android:
Serialize and deserialize custom data types:
@Serializable data class UserProfile(val name: String, val age: Int) // Write custom data dataStore.edit { preferences -> preferences[KEY_USER_PROFILE] = UserProfile("John Doe", 25) } // Read custom data val userProfile: Flow<UserProfile?> = dataStore.data.map { preferences -> preferences[KEY_USER_PROFILE] } Reading and writing data with Preferences DataStore:
Use the edit function to write data and access data using the data property. Combine with map for transformations.
Preferences DataStore and Jetpack Navigation in Android:
Access DataStore in different fragments or activities. Share the same DataStore instance to maintain consistency across the app.
Preferences DataStore and Kotlin Coroutines:
Use coroutines to perform asynchronous operations with DataStore. Wrap data access operations with withContext(Dispatchers.IO).
Preferences DataStore with encrypted preferences in Android:
Use Android's EncryptedSharedPreferences or consider encrypting the data before storing it in DataStore for enhanced security.
Preferences DataStore and LiveData integration:
Convert Flow to LiveData for easier integration with UI components:
val userIdLiveData: LiveData<String?> = userId.asLiveData()
Handling data changes with Preferences DataStore:
Use the collect function on the Flow to observe changes in the data:
nameFlow.collect { name -> Log.d(TAG, "Name: $name") } rtmp nltk broken-pipe mule-esb regsvr32 sonata-admin web-manifest ngx-datatable log4j2 greatest-n-per-group