Preference Data Store is used to store data permanently in android. Earlier we had to Shared Preferences for the same but since it is deprecated we are using Data Store now. A sample video is given at the end to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Kotlin language.
Step by Step Implementation
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.
Note that select Kotlin as the programming language
Step 2: Add dependency inside build.gradle(app)
Add the Data Store and Livedata dependency inside the build.gradle.kts (Module :app) and click on the sync now button.
dependencies {
...
implementation ("androidx.datastore:datastore-preferences:1.1.6")
// livedata - optional
implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")
}
Step 3: Working with the activity_main.xml file
Go to the activity_main.xml file and refer to the following code. Below is the code for the activity_main.xml file. This is for the basic layout used in the app.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_margin="32dp"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10"
android:hint="Name" />
<EditText
android:id="@+id/et_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Age"
android:inputType="number" />
<Button
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="32dp"
android:text="Save & Display user" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Age"
android:textColor="@color/black"
android:textSize="20sp" />
</LinearLayout>
Step 4: Working with the UserManager.kt class
Create a new kotlin class and name it UserManager, this class holds the code for saving and retrieving data from the preference Data Store. Comments are added inside the code to understand the code in more detail.
UserManager.kt:
package org.geeksforgeeks.demo
import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
// Create an instance of the datastore at the top level of your kotlin file
val Context.myDataStore by preferencesDataStore(name = "user_prefs")
class UserManager (
private val context: Context
) {
// Create keys to store and retrieve the data
companion object {
val USER_AGE_KEY = intPreferencesKey("USER_AGE")
val USER_NAME_KEY = stringPreferencesKey("USER_NAME")
}
// function to store user data
suspend fun storeUser(age: Int, name: String) {
context.myDataStore.edit {
it[USER_AGE_KEY] = age
it[USER_NAME_KEY] = name
}
}
// Create an age flow to retrieve age from the preferences
val userAgeFlow: Flow<Int> = context.myDataStore.data.map {
it[USER_AGE_KEY] ?: 0
}
// Create a name flow to retrieve name from the preferences
val userNameFlow: Flow<String> = context.myDataStore.data.map {
it[USER_NAME_KEY] ?: ""
}
}
Step 5: Working with the MainActivity.kt file
Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.
MainActivity.kt:
package org.geeksforgeeks.demo
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.asLiveData
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
// initialize the ui elements
private lateinit var etName: EditText
private lateinit var etAge: EditText
private lateinit var tvName: TextView
private lateinit var tvAge: TextView
private lateinit var saveButton: Button
// initialize the user manager class
private lateinit var userManager: UserManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// define the ui elements
etName = findViewById(R.id.et_name)
etAge = findViewById(R.id.et_age)
tvName = findViewById(R.id.tv_name)
tvAge = findViewById(R.id.tv_age)
saveButton = findViewById(R.id.btn_save)
// Get reference of the userManager class
userManager = UserManager(this)
// on click of save button
saveButton.setOnClickListener {
// call function for saving data to the preference data store
buttonSave()
}
// call function to retrieve the saved data
observeData()
}
// function to save data
private fun buttonSave() {
// Gets the user input and saves it
val name = etName.text.toString().trim()
val ageText = etAge.text.toString().trim()
// Validate name
if (name.isEmpty()) {
etName.error = "Name cannot be empty"
return
}
// Validate age
if (ageText.isEmpty()) {
etAge.error = "Age cannot be empty"
return
}
val age = try {
ageText.toInt()
} catch (e: NumberFormatException) {
etAge.error = "Invalid age"
return
}
// Stores the values
// Since the storeUser() is a suspend function, it has to be launched in a coroutine scope
lifecycleScope.launch {
userManager.storeUser(age, name)
}
}
// function to retrieve data
private fun observeData() {
// Updates age
// every time user age changes it will be observed by userAgeFlow
this.userManager.userAgeFlow.asLiveData().observe(this) {
tvAge.text = "Age: $it"
}
// Updates name
// every time user name changes it will be observed by userNameFlow
userManager.userNameFlow.asLiveData().observe(this) {
tvName.text = "Name: $it"
}
}
}