💾 Data, Network और Architecture · Lesson 29
SharedPreferences और DataStore
यहाँ क्या store करें
Key–value storage छोटी settings के लिए use करें: user name, dark mode on/off, "onboarding देखा", आख़िरी selected tab। Records की lists (notes, products) के लिए database (Room) use करें।
SharedPreferences basics
Kotlin
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
// write
prefs.edit { // androidx.core.content.edit
putString("user_name", "Riya")
putBoolean("dark_mode", true)
putInt("launch_count", 5)
}
// read (always give a default)
val name = prefs.getString("user_name", "Student")
val dark = prefs.getBoolean("dark_mode", false)
val count = prefs.getInt("launch_count", 0)
// remove / clear
prefs.edit { remove("user_name") }
prefs.edit { clear() }साफ़ wrapper class
हर जगह keys दोहराने की जगह final app preferences को Kotlin properties वाली एक class में रखती है:
Kotlin – data/SettingsStore.kt
package com.codingeasily.studentdiary.data
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
/** Small key-value settings saved with SharedPreferences. */
class SettingsStore(context: Context) {
private val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var userName: String
get() = prefs.getString(KEY_NAME, "Student") ?: "Student"
set(value) = prefs.edit { putString(KEY_NAME, value) }
var darkMode: Boolean
get() = prefs.getBoolean(KEY_DARK, false)
set(value) = prefs.edit { putBoolean(KEY_DARK, value) }
var remindersEnabled: Boolean
get() = prefs.getBoolean(KEY_REMINDERS, true)
set(value) = prefs.edit { putBoolean(KEY_REMINDERS, value) }
fun applyTheme() {
AppCompatDelegate.setDefaultNightMode(
if (darkMode) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO
)
}
companion object {
private const val KEY_NAME = "user_name"
private const val KEY_DARK = "dark_mode"
private const val KEY_REMINDERS = "reminders"
}
}Kotlin – use करना
// Student Diary – SettingsFragment
settings = SettingsStore(requireContext())
binding.etName.setText(settings.userName)
binding.btnSaveName.setOnClickListener { settings.userName = binding.etName.text.toString() }
// MainActivity.onResume – show it in the drawer header
header.tvUserName.text = getString(R.string.hello_user, SettingsStore(this).userName)Example: first launch / onboarding
Kotlin
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val prefs = getSharedPreferences("app", MODE_PRIVATE)
val seen = prefs.getBoolean("onboarding_done", false)
startActivity(Intent(this, if (seen) MainActivity::class.java else OnboardingActivity::class.java))
finish()
}
}
// OnboardingActivity – when the user taps "Get started"
getSharedPreferences("app", MODE_PRIVATE).edit { putBoolean("onboarding_done", true) }Preferences DataStore
DataStore modern replacement है: यह asynchronous है (UI कभी block नहीं), values Flow के रूप में देता है और errors safely संभालता है।
TOML + Kotlin DSL
// libs.versions.toml
datastore = "1.1.1"
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
// app/build.gradle.kts
implementation(libs.androidx.datastore.preferences)Kotlin
// One DataStore per file – declared at top level of a Kotlin file
val Context.dataStore by preferencesDataStore(name = "settings")
object Keys {
val USER_NAME = stringPreferencesKey("user_name")
val DARK_MODE = booleanPreferencesKey("dark_mode")
}
class SettingsRepository(private val context: Context) {
// read as a Flow – the UI updates whenever the value changes
val userName: Flow<String> = context.dataStore.data.map { it[Keys.USER_NAME] ?: "Student" }
suspend fun setUserName(name: String) {
context.dataStore.edit { it[Keys.USER_NAME] = name }
}
}
// Fragment
viewLifecycleOwner.lifecycleScope.launch {
repo.userName.collect { binding.tvHello.text = "Hello, $it" }
}
binding.btnSave.setOnClickListener {
viewLifecycleOwner.lifecycleScope.launch { repo.setUserName(binding.etName.text.toString()) }
}SharedPreferences vs DataStore vs Room
| SharedPreferences | DataStore | Room | |
|---|---|---|---|
| Data | छोटे key–values | छोटे key–values | Records की tables |
| API | Synchronous get, async apply | Flow + suspend | DAO, Flow, SQL |
| Main-thread safe | ज़्यादातर | हाँ | हाँ (coroutines के साथ) |
| किसके लिए best | Simple apps, quick flags | नई apps, observed settings | Notes, products, orders |
आम गलतियाँ
- अलग-अलग जगह अलग file names (
"settings"vs"Settings") → values खोई लगती हैं। - Preferences में बड़ी JSON lists → धीमा; Room use करें।
- एक ही file के लिए दो DataStore instances → crash; top level पर एक बार declare करें।
सारांश
getSharedPreferences(name, MODE_PRIVATE)+edit { putX }+getX(key, default)।- Keys को properties वाली class (SettingsStore) में रखें।
- DataStore = नए code के लिए Flow-based, async विकल्प।
✅ Practice
App कितनी बार खुली गिनिए और home screen पर "Welcome back! Visit #5" दिखाइए। फिर वही feature DataStore से दोबारा लिखिए।
अक्सर पूछे जाने वाले प्रश्न (FAQ)
SharedPreferences data कहाँ save होता है?
App के private folder (/data/data//shared_prefs/) में एक XML file में। App uninstall या data clear करने पर delete हो जाता है।
क्या password या token store करना safe है?
Passwords store न करें। Login tokens के लिए normal apps में private storage आमतौर पर ठीक है; sensitive apps में value encrypt करें या Android Keystore use करें।
apply() या commit()?
apply() background में save करके तुरंत लौटता है — यही use करें। commit() लिखने तक रोकता है। KTX edit { } default रूप से apply() use करता है।
