Preferences DataStore in Android

Last Updated : 23 Jul, 2025

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
<?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 &amp; 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:

Kotlin
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:

Kotlin
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"
        }
    }
}

Output:


Comment

Explore