SharedPreferences
NSUserDefaults
Android vs iOS
data storage
mobile development

Android equivalent of NSUserDefaults in iOS

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you come from iOS, the closest traditional Android equivalent to NSUserDefaults is SharedPreferences. Both store small pieces of application data as key-value pairs. In modern Android code, though, it is worth knowing that Jetpack DataStore is now often preferred for new work because it offers a cleaner async API and fewer consistency issues.

The Direct Mapping: SharedPreferences

NSUserDefaults is commonly used for settings such as theme choice, last login flag, or a saved username. On Android, SharedPreferences serves the same role.

A basic example in Kotlin looks like this:

kotlin
1val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
2
3prefs.edit()
4    .putBoolean("dark_mode", true)
5    .putString("display_name", "Ada")
6    .apply()
7
8val darkMode = prefs.getBoolean("dark_mode", false)
9val displayName = prefs.getString("display_name", "Guest")

The pattern is familiar if you have used defaults on iOS:

  • choose a key
  • write a primitive value
  • read it later with a fallback default

This is appropriate for small user preferences and lightweight app state.

apply() vs commit()

When writing preferences, Android gives you two main choices.

apply() updates the in-memory value immediately and writes to disk asynchronously. It is usually the right default for UI code.

commit() writes synchronously and returns a success flag. That can be useful when you absolutely need to know the write finished, but it blocks longer and is used less often.

kotlin
1val success = prefs.edit()
2    .putInt("launch_count", 10)
3    .commit()
4
5println(success)

For most settings screens, apply() is simpler and better aligned with normal app responsiveness.

Activity-Specific vs App-Wide Preferences

Android offers more than one way to access preferences. The most common is getSharedPreferences(name, MODE_PRIVATE), which creates or opens a named file shared across the app.

If you only want data scoped to one activity, there is also getPreferences(MODE_PRIVATE). In practice, named shared preferences are usually clearer because they make the storage file explicit.

A wrapper class helps keep keys in one place:

kotlin
1class SettingsRepository(context: Context) {
2    private val prefs = context.getSharedPreferences("app_settings", Context.MODE_PRIVATE)
3
4    fun setDarkMode(enabled: Boolean) {
5        prefs.edit().putBoolean("dark_mode", enabled).apply()
6    }
7
8    fun isDarkModeEnabled(): Boolean {
9        return prefs.getBoolean("dark_mode", false)
10    }
11}

This is easier to maintain than scattering hard-coded keys through multiple activities.

Why Many Android Apps Use DataStore Now

While SharedPreferences is the historical equivalent, new Android projects often use DataStore instead. DataStore avoids some of the old API's awkwardness and works naturally with coroutines and flows.

A minimal preferences DataStore example looks like this:

kotlin
1val Context.dataStore by preferencesDataStore(name = "app_settings")
2
3object Keys {
4    val DARK_MODE = booleanPreferencesKey("dark_mode")
5}
6
7suspend fun saveDarkMode(context: Context, enabled: Boolean) {
8    context.dataStore.edit { prefs ->
9        prefs[Keys.DARK_MODE] = enabled
10    }
11}

That does not change the answer to the original question. The conceptual equivalent is still SharedPreferences. It just means modern Android developers should know there is a newer option with better ergonomics.

What Kind of Data Belongs Here

Like NSUserDefaults, Android preference storage is for small configuration values, not for large structured data. Good examples include:

  • theme choice
  • onboarding completed flag
  • selected language code
  • remembered sort option

Poor examples include:

  • large cached API responses
  • images or files
  • relational data better suited to Room or SQLite
  • secrets that should be stored with stronger protection

Common Pitfalls

A common mistake is treating SharedPreferences as a general-purpose database. It is for small key-value settings, not for complex domain data.

Another issue is duplicating raw string keys all over the codebase. A wrapper class or constants object reduces typing errors and makes refactoring safer.

Developers also sometimes assume apply() means the data is immediately durable on disk. It updates memory first and writes asynchronously, which is fine for most settings but worth understanding.

Finally, if you are starting a new Android app, do not stop at the old analogy. SharedPreferences is the classic equivalent to NSUserDefaults, but DataStore may be the better implementation choice.

Summary

  • The traditional Android equivalent of NSUserDefaults is SharedPreferences.
  • Use it for small key-value settings and lightweight app state.
  • Prefer apply() for most writes and commit() only when synchronous completion matters.
  • Keep keys centralized instead of scattering string literals across the app.
  • For new Android projects, consider DataStore as the modern alternative.

Course illustration
Course illustration

All Rights Reserved.