Android Jetpack Data Store: A Comprehensive Guide to Modern Data Storage
Introduction
Hello everyone! In this article, we will explore Jetpack Data Store and even build a simple application to demonstrate its capabilities. While discussing Data Store, it’s essential to also remember other Android data storage methods like Shared Preferences and Room.
What is Data Store?
Data Store is a modern storage solution from Android that utilizes Key-Value pairs similar to Shared Preferences. It also incorporates Flow and Coroutines for better performance and efficiency.
Note: In Pro versions, DataStore can generate a schema based on the objects you define.
_getPreferences.getString("foodName", foodName)
key value
Types of Storage Keys
The Android Developer site provides us with different types of storage keys:
booleanPreferencesKey
doublePreferencesKey
floatPreferencesKey
intPreferencesKey
longPreferencesKey
stringPreferencesKey
stringSetPreferencesKey
Why Use Data Store?
Here are some advantages of using Data Store:
- Runtime Exception Safety: Data Store minimizes runtime exceptions.
- Success and Error Handling: When setting data, you can easily handle both success and error cases.
- Read and Write: Data Store allows for both reading and writing of data.
- Asynchronous Programming: With the use of Flow and Coroutines, asynchronous programming becomes seamless.
- Type Safety: If you’re using Pro DataStore, the compiler will enforce type safety for you.
Coding Time
Dependencies
implementation("androidx.datastore:datastore-preferences:1.0.0")implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
Creating a Simple Product App
Our sample app will include the following fields:
- Product Name (String)
- Product Price (Int)
- Is Sold (Boolean)
First, let’s create a class to manage DataStore:
Create variable for for use data store.
private val Context.datastore: DataStore<Preferences> by preferencesDataStore("products")private val myDatastore: DataStore<Preferences> = context.datastore
For Key
val PRODUCT_NAME= stringPreferencesKey("PRODUCT_NAME")
val PRODUCT_PRICE= intPreferencesKey("PRODUCT_PRICE")
val IS_SOLD = booleanPreferencesKey("IS_SOLD")
I will use Coroutine and create suspend functions
suspend fun storeProductData(
productName: String,
productPrice: Int,
isSold: Boolean
) {
myDatastore.edit { preferences ->
preferences[PRODUCT_NAME] = productName
preferences[PRODUCT_PRICE] = productPrice
preferences[IS_SOLD] = isSold
}
}
For Flow
val productNameFlow: Flow<String> = myDatastore.data.map {
it[PRODUCT_NAME] ?: ""
}
val productPriceFlow: Flow<Int> = myDatastore.data.map {
it[PRODUCT_PRICE] ?: 0
}
val productIsSoldFlow: Flow<Boolean> = myDatastore.data.map {
it[IS_SOLD] ?: false
}
VİEW
Page 1 (Save Data)
val isSold: Boolean = _binding.switchIsSold.isChecked
I made a suspend function for Coroutine in our manager file above, let’s call it here and get our data from the UI.
CoroutineScope(Dispatchers.IO).launch {
_productManager.storeProductData(
_binding.etProductName.text.toString(),
_binding.etProductPrice.text.toString().toInt(),
isSold
)
}
Page 2 (Observe Data)
The general observe code structure will be as follows. asLiveData helps us to Observe.
_productManager.productNameFlow.asLiveData()
.observe(this) { productName ->
productName?.let {
_binding.tvProductName.text = productName
}
}
or
lifecycleScope.launchWhenStarted {
_productManager.productSellingLocationFlow.collect{
location ->
location?.let {
_binding.etCreateLocation.setText(location)
}
}
}
App Demo
Thanks
https://developer.android.com/topic/libraries/architecture/datastore