Interview QuestionPractical QuestionFollow-up Questions

Local Data Persistence on Android

skydovesJaewoong Eum (skydoves)||9 min read

Local Data Persistence on Android

Android provides several mechanisms for storing and persisting data locally, each designed for different data shapes and access patterns. Choosing the right storage solution depends on whether the data is simple key value pairs, structured relational records, or raw binary files. Understanding the tradeoffs between SharedPreferences, DataStore, Room, and file storage is a common interview topic because it reveals how well a developer understands Android's data layer. By the end of this lesson, you will be able to:

  • Describe the purpose and limitations of SharedPreferences for key value storage.
  • Explain how Jetpack DataStore improves on SharedPreferences with asynchronous, coroutine based APIs.
  • Identify when Room is the appropriate choice for structured, relational data.
  • Distinguish between internal and external file storage for binary or custom data.

SharedPreferences

SharedPreferences is the oldest key value storage mechanism on Android. It stores primitive types like Boolean, Int, String, and Float in an XML file on disk. The data persists across app restarts and is private to the application by default.

val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
prefs.edit {
    putString("user_name", "skydoves")
}
val name = prefs.getString("user_name", "")

SharedPreferences reads are synchronous and load the entire file into memory on first access. Writes through apply() are asynchronous but can block the main thread during Activity.onPause() if pending writes have not flushed. The commit() method writes synchronously and returns a success boolean, which blocks the calling thread until the write completes.

SharedPreferences does not support type safety, schema evolution, or structured data. It is suitable for small amounts of configuration data like user preferences or feature flags, but it becomes problematic for larger or more complex data sets.

Jetpack DataStore

Jetpack DataStore is the modern replacement for SharedPreferences. It provides two implementations: Preferences DataStore for key value storage and Proto DataStore for structured data using Protocol Buffers.

DataStore is built on Kotlin coroutines and Flow, making all reads and writes asynchronous by default. This eliminates the main thread blocking issues that SharedPreferences can cause:

val dataStore: DataStore<Preferences> =
    context.createDataStore(name = "settings")

val userNameKey = stringPreferencesKey("user_name")
suspend fun saveUserName(name: String) {
    dataStore.edit { settings ->
        settings[userNameKey] = name
    }
}

val userNameFlow: Flow<String> = dataStore.data.map { prefs ->
    prefs[userNameKey] ?: ""
}

DataStore guarantees atomicity and consistency. It writes to a new file and renames it on success, which prevents partial writes from corrupting data. Proto DataStore adds type safety and schema validation through generated Protocol Buffer classes, making it suitable for structured configuration that evolves over time.

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor