Did you ever wonder how to store some values on your application without losing them after closing the app? Android provides a way to do that if you have a small collection of key values you’d like to save!
In this article, we’ll take a look at Android’s SharedPreferences
APIs and then demonstrate how to use SharedPreferences
in a use case.
Jetpack DataStore is a modern solution that uses Kotlin coroutines and Flow to store data asynchronously. In the future, you might consider migrating to Jetpack DataStore from SharedPreferences
. However, in this article we’ll focus on SharedPreferences
since it remains useful and is still very popular as of this writing.
Jump ahead:
SharedPreferences
?SharedPreferences
is an Android API that allows you to create and access a file containing a key-values collection. A SharedPreferences
object provides some methods for reading and writing these values on the file. Each SharedPreferences
file is managed by the framework and can be private to the application or shared.
SharedPreferences
filesTo create or access a SharedPreferences
file, you can call either of the following methods: getSharedPreferences()
or getDefaultSharedPreferences()
.
Let’s take a look.
Use the getSharedPreferences() method if you need to create or access a SharedPreferences
file identified by name.
Here’s an example of this method:
val sharedPreferences = activity?.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)
Use the getDefaultSharedPreferences() method to get the default SharedPreferences file for an entire app. You should be aware that this method requires extra dependency.
The below example of this method requires an extra dependency to be added to the build.gradle
file at the app module level:
Here’s the dependency:
implementation "androidx.preference:preference-ktx:1.2.0"
Here’s an example of the method:
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
SharedPreferences
filesThe second parameter of the getSharedPreferences
method is the mode. This parameter relates to permissions for file sharing.
To share private files with applications that do not share your user ID, you can use MODE_WORLD_READABLE
with Android versions older than 7.0. Android 7.0+ will throw a security exception if you attempt to use this mode; it has been deprecated since API level 17.
If you run into this issue, a workaround is to use a FileProvider with the intent set to FLAG_GRANT_READ_URI_PERMISSION
. For more information, also see the official documentation on sharing files.
To share private files with any application that shares your user ID, you can use MODE_PRIVATE
.
SharedPreferences
filesTo retrieve values from a SharedPreferences
file, you can call any of the below methods, providing the key for the value you want and an optional default value to return if the key doesn’t exist:
contains(key: String)
Use this method to check if the preferences file contains a specific preferenceedit()
Use this method to create a new Editor, through which you can make atomic changes to the data in the SharedPreferences
filegetAll()
Use this method to retrieve all values in the SharedPreferences
filegetInt(key: String, defValue: Integer)
Use this method to retrieve an Integer
value from the SharedPreferences
filegetBoolean(key: String, defValue: Boolean)
Use this method to retrieve a Boolean
value from the SharedPreferences
filegetFloat(key: String, defValue: Float)
Use this method to retrieve a Float
value from the SharedPreferences
filegetLong(key: String, defValue: Long)
Use this method to retrieve a Long
value from the SharedPreferences
filegetString(key: String, defValue: String)
Use this method to retrieve a String
value from the SharedPreferences
filegetStringSet(key: String, defValues: Set)
Use this method to retrieve a set of String
values from the SharedPreferences
fileSharedPreferences
filesTo write values in a SharedPreferences
file, create a SharedPreferences.Editor
by calling edit()
on your SharedPreferences
object. With edit()
, you’ll be able to call the following methods:
putInt(key: String, value: Integer)
Use this method to insert an Integer
value on the SharedPreferences
fileputBoolean(key: String, value: Boolean)
Use this method to insert a Boolean
value on the SharedPreferences
fileputFloat(key: String, value: Float)
Use this method to insert a Float
value on the SharedPreferences
fileputLong(key: String, value: Long)
Use this method to insert a Long
value on the SharedPreferences
fileputString(key: String, value: String)
Use this method to insert a String
value on the SharedPreferences
fileputStringSet(key: String, values: Set)
Use this method to insert a set of String
values on the SharedPreferences
fileAfter writing changes, be sure to call apply()
or commit()
to save your changes. According to the official Android documentation, both apply()
and commit()
change the in-memory SharedPreferences
object immediately but write updates to the disk differently. apply()
writes updates asynchronously, whereas commit()
writes updates synchronously and could result in paused UI rendering if called from the main thread.
Here’s an example illustrating some of the above functions to retrieve and write values in a SharedPreferences
file:
val sharedPref = activity?.getPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE) ?: return with (sharedPref.edit()) { putInt(getString(R.string.saved_high_score_key), newHighScore) apply() }
SharedPreferences
filesTo detect changes in a SharedPreferences
file, you can call the following methods:
registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferencechangeListener)
Use this method to register a callback that gets invoked when a change happens in the SharedPreferences
fileunregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferencechangeListener)
Use this method to unregister a callback that gets invoked when a change happens in the SharedPreferences
fileSharedPreferences
use caseNow, we’ll take a look at a common scenario in which SharedPreferences
may be useful. Let’s say you want to display an onboarding page the first time a user opens an app.
To make this work, you’ll need to have a Boolean value stored in a SharedPreferences
file indicating whether or not it is the first time a particular user has opened the app.
To start, open res/values/strings.xml
and add the name of our SharedPreferences
file.
Next, add the following code to the strings.xml
file:
<string name="app_shared_prefs">com.pp.sharedprefs.PREFERENCES_FILE_KEY</string>
You’ll also need to add a key that identifies our stored value. Let’s call it FIRST_TIME_OPENING_KEY
.
Add the following code to the strings.xml
file:
<string name="first_time_opening">FIRST_TIME_OPENING_KEY</string>
Now, go to your activity and add the following code inside onCreate(savedInstanceState: Bundle?)
after setContentView()
is called:
getSharedPreferences(getString(R.string.app_shared_prefs), Context.MODE_PRIVATE)?.let { sharedPreferences -> val isFirstTimeOpening = sharedPreferences.getBoolean(getString(R.string.first_time_opening), true) if (isFirstTimeOpening) { showOnboarding() with (sharedPreferences.edit()) { putBoolean(getString(R.string.first_time_opening), false) apply() } } }
In the above code, we get access to the file by calling getSharedPreferences(name, mode)
.
Next, we try to get the value of our FIRST_TIME_OPENING_KEY
from the SharedPreferences
file. If the value is nonexistent, we return true
.
If we return true
, this is the first time the user is opening the app. In this case, we show the onboarding screen and change the value of FIRST_TIME_OPENING_KEY
to false
so the user will not see the onboarding screen again. Then, we call apply()
to conclude the changes.
That should do it!
In our use case example, we handled an onboarding screen. However, this solution works for anything that you want to be run only once, when the user opens the app for the first time.
Since we’re using Kotlin, we can use its power to reduce the code length a bit with Kotlin extensions.
To use Kotlin extensions, create a separate file called SharedPreferencesHelper
and then add the following:
fun SharedPreferences.edit(actions: SharedPreferences.Editor.() -> Unit) { with (edit()) { actions(this) apply() } }
The above code will add an extension function called edit
to the SharedPreferences interface
. The edit()
function takes a Kotlin lambda function, which is defined by curly braces and is an extension of SharedPreferences.Editor
.
On this extension function, we are already calling apply()
at the end, so there’s no need to repeat that when using this extension to add values in the SharedPreferences
file.
Go back to the Activity, and replace the following code:
with (sharedPreferences.edit()) { putBoolean(getString(R.string.first_time_opening), false) apply() }
With the following snippet:
sharedPreferences.edit { putBoolean(getString(R.string.first_time_opening), false) }
This shorter code should provide the same result!
In this article, we investigated and offered solutions for using the Kotlin SharedPreferences
API. We also demonstrated how to use SharedPreferences
in an example involving an onboarding screen.
For more information on this topic, check out the official docs on: SharedPreferences, Jetpack DataStore, and Kotlin extensions.
Thank you for reading. I hope this article makes your life easier while working with SharedPreferences
!
LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your Android apps — try LogRocket for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.