Welcome back, fellow Android app developers! In today’s blog post, we’re diving deep into the realm of data storage in Android applications, specifically focusing on Shared Preferences and how to store various types of data using Kotlin.
By the end of this tutorial, you’ll have a solid understanding of how to efficiently manage different data types in Shared Preferences and implement them in a real-world example project.
Table of Content
What is Shared Preferences?
Shared Preferences is a key-value pair storage system provided by Android for persisting simple data types. It’s commonly used to store user preferences, settings, and small amounts of data that need to be quickly accessed.
In this tutorial, we’ll explore how to utilize Shared Preferences to store and retrieve different data types such as strings, integers, booleans, and sets.
Creating a New Project
Let’s kick things off by setting up a simple Android project. Ensure you have the latest version of Android Studio installed and create a new project with an empty activity.
Project Setup
Open Android Studio, click on “Start a new Android Studio project,” and follow the wizard. Choose an empty activity to keep things minimal.
How to Create a New Project in Android Studio
Define the DataModel Class
Create a Kotlin data class that represents the data structure you want to store in Shared Preferences. For our example, let’s create a UserData
data class.
package com.example.sharedpref
data class UserData(
val username: String,
val age: Int,
val isPremiumUser: Boolean,
val favoriteSubjects: Set<String>
)
Implement Shared Preferences Manager
Create a SharedPreferencesManager
class responsible for handling the storing and retrieving of data in Shared Preferences.
package com.example.sharedpref
import android.content.Context
import android.content.SharedPreferences
class SharedPrefManager(context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
fun saveUserData(userData: UserData) {
with(sharedPreferences.edit()) {
putString("username", userData.username)
putInt("age", userData.age)
putBoolean("isPremiumUser", userData.isPremiumUser)
putStringSet("favoriteGenres", userData.favoriteSubjects)
apply()
}
}
fun getUserData(): UserData {
return UserData(
sharedPreferences.getString("username", "") ?: "",
sharedPreferences.getInt("age", 0),
sharedPreferences.getBoolean("isPremiumUser", false),
sharedPreferences.getStringSet("favoriteGenres", setOf()) ?: setOf()
)
}
}
Storing and Retrieving
Create Layout
Navigate to the activity_main.xml
file and replace the existing code with the following.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:title="Shared Preferences" />
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="Username">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="Age">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="3" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/premium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Premium subscriptions" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/subject_list"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:singleSelection="false">
<com.google.android.material.chip.Chip
android:id="@+id/kotlin"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kotlin" />
<com.google.android.material.chip.Chip
android:id="@+id/python"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Python" />
<com.google.android.material.chip.Chip
android:id="@+id/android"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android" />
</com.google.android.material.chip.ChipGroup>
<Button
android:id="@+id/save_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Save profile" />
<com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/username_load"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="8dp"
android:text="Username"
android:textAppearance="?attr/textAppearanceTitleLarge"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/age_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Age"
android:textAppearance="?attr/textAppearanceTitleMedium" app:layout_constraintStart_toStartOf="@id/username_load" app:layout_constraintTop_toBottomOf="@id/username_load" />
<TextView
android:id="@+id/premium_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Premium"
android:textAppearance="?attr/textAppearanceTitleMedium"
app:layout_constraintStart_toEndOf="@id/age_load" app:layout_constraintTop_toBottomOf="@id/username_load" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/subject_list_load"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="@id/age_load" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Store and Retrieve Data
Navigate to the MainActivity.kt
class and replace the existing code with the following.
package com.example.sharedpref
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.sharedpref.databinding.ActivityMainBinding
import com.google.android.material.chip.Chip
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var sharedPref: SharedPrefManager
private val favoriteSubjects = mutableSetOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
sharedPref = SharedPrefManager(this)
binding.subjectList.setOnCheckedStateChangeListener { group, _ ->
for (index in 0 until group.childCount) {
val chip = group.getChildAt(index) as Chip
if (chip.isChecked) {
favoriteSubjects.add(chip.text.toString())
}
}
}
// Storing and Retrieving Different Data Types
binding.saveData.setOnClickListener {
val username = binding.username.text.toString()
val age = binding.age.text.toString().toInt()
val premiumStatus = binding.premium.isChecked
// Storing String, Integer, Boolean, and Set Data
sharedPref.saveUserData(
UserData(
username = username,
age = age,
isPremiumUser = premiumStatus,
favoriteSubjects = favoriteSubjects
)
)
// Retrieving String, Integer, Boolean, and Set Data
val userData = sharedPref.getUserData()
binding.usernameLoad.text = userData.username
binding.ageLoad.text = "${userData.age}Years"
if (userData.isPremiumUser) {
binding.premiumLoad.text = "Premium"
} else {
binding.premiumLoad.text = "Free"
}
val chipNames = userData.favoriteSubjects
for (chipName in chipNames) {
val chip = Chip(this)
chip.text = chipName
binding.subjectListLoad.addView(chip)
}
}
}
}
Testing the App
Here is the final output. Launch the app, input all data, and click on the Save profile button.
Conclusion
Congratulations! You’ve successfully learned how to store and retrieve different data types in Shared Preferences using Kotlin. This knowledge is crucial for building efficient and user-friendly Android applications.
Feel free to apply these techniques to your projects and explore further improvements, such as error handling and validation, to enhance the robustness of your data storage mechanisms. Happy coding!