Preferences DataStore in Android
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 below 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, Lifecycle, and Coroutines dependency inside the build.gradle(app) and click on the sync now button.
// Preferences DataStore
implementation “androidx.datastore:datastore-preferences:1.0.0-alpha01”
// Lifecycle components
implementation “androidx.lifecycle:lifecycle-livedata-ktx:2.2.0”
implementation “androidx.lifecycle:lifecycle-extensions:2.2.0”
implementation “androidx.lifecycle:lifecycle-common-java8:2.2.0”
implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0”
// Kotlin coroutines components
implementation “org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.10”
api “org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1”
api “org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1”
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.
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_horizontal" android:orientation = "vertical" tools:context = ".MainActivity" > < EditText android:id = "@+id/et_name" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:layout_marginTop = "20dp" android:ems = "10" android:hint = "Name" /> < EditText android:id = "@+id/et_age" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:ems = "10" android:hint = "Age" android:inputType = "number" /> < Button android:id = "@+id/btn_save" android:layout_width = "150dp" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:background = "#FF7043" android:padding = "10dp" android:text = "Save user" android:textColor = "@android:color/white" /> < TextView android:id = "@+id/tv_name" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:text = "Name" android:textColor = "@android:color/black" android:textSize = "20sp" /> < TextView android:id = "@+id/tv_age" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_margin = "10dp" android:text = "Age" android:textColor = "@android: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.
Kotlin
import android.content.Context import androidx.datastore.preferences.createDataStore import androidx.datastore.preferences.edit import androidx.datastore.preferences.preferencesKey import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map class UserManager(context: Context) { // Create the dataStore and give it a name same as shared preferences private val dataStore = context.createDataStore(name = "user_prefs" ) // Create some keys we will use them to store and retrieve the data companion object { val USER_AGE_KEY = preferencesKey<Int>( "USER_AGE" ) val USER_NAME_KEY = preferencesKey<String>( "USER_NAME" ) } // Store user data // refer to the data store and using edit // we can store values using the keys suspend fun storeUser(age: Int, name: String) { dataStore.edit { it[USER_AGE_KEY] = age it[USER_NAME_KEY] = name // here it refers to the preferences we are editing } } // Create an age flow to retrieve age from the preferences // flow comes from the kotlin coroutine val userAgeFlow: Flow<Int> = dataStore.data.map { it[USER_AGE_KEY] ?: 0 } // Create a name flow to retrieve name from the preferences val userNameFlow: Flow<String> = dataStore.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.
Kotlin
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.observe import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { lateinit var etName: EditText lateinit var etAge: EditText lateinit var tvName: TextView lateinit var tvAge: TextView lateinit var saveButton: Button lateinit var userManager: UserManager var age = 0 var name = "" override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) 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 to our userManager class userManager = UserManager( this ) // this function saves the data to // preference data store on click of // save Button buttonSave() // this function retrieves the saved data // as soon as they are stored and even // after app is closed and started again observeData() } private fun buttonSave() { // Gets the user input and saves it saveButton.setOnClickListener { name = etName.text.toString() age = etAge.text.toString().toInt() // Stores the values // Since the storeUser function of UserManager // class is a suspend function // So this has to be done in a coroutine scope GlobalScope.launch { userManager.storeUser(age, name) } } } private fun observeData() { // Updates age // every time user age changes it will be observed by userAgeFlow // here it refers to the value returned from the userAgeFlow function // of UserManager class this .userManager.userAgeFlow.asLiveData().observe( this ) { age = it tvAge.text = it.toString() } // Updates name // every time user name changes it will be observed by userNameFlow // here it refers to the value returned from the usernameFlow function // of UserManager class userManager.userNameFlow.asLiveData().observe( this ) { name = it tvName.text = it.toString() } } } |
Output:
Github repo here.
Contact Us