首页 / Android 入门教程 / SharedPreferences

Android 入门教程

SharedPreferences

本教程共 100 篇 · 第 65 篇 · 更新于 2026-07-28 · 约 8 分钟阅读

AndroidAndroid 入门教程SharedPreferencesDataStore键值对存储偏好设置

65. SharedPreferences

本节目标:学会用 SharedPreferences 读写键值对数据,理解 commit 与 apply 的区别,了解 DataStore 作为现代替代方案。

SharedPreferences 是什么

SharedPreferences(简称 SP)是 Android 的轻量级键值对存储方案。适合存少量简单数据,比如用户设置、登录标志、主题偏好。

打个比方:SP 像一张便签纸,你记几个关键配置(「深色模式:开」「语言:中文」),下次打开应用时直接读。不适合记大量或复杂的数据。

获取 SharedPreferences 实例

两种方式:

// 方式一:指定文件名,整个应用共享
val sp = context.getSharedPreferences("user_settings", Context.MODE_PRIVATE)

// 方式二:Activity 专属,不需要文件名
val sp = getPreferences(Context.MODE_PRIVATE)
Note
  • MODE_PRIVATE 表示只有本应用能访问。早期还有 MODE_WORLD_READABLE / MODE_WORLD_WRITABLE 让其他应用访问,但已废弃,现在只能用 MODE_PRIVATE。文件名建议用应用包名做前缀,如 com.example.app.settings

写入数据

val sp = getSharedPreferences("settings", Context.MODE_PRIVATE)
val editor = sp.edit()

editor.putString("username", "张三")
editor.putInt("age", 25)
editor.putBoolean("darkMode", true)
editor.putFloat("score", 95.5f)
editor.putLong("loginTime", System.currentTimeMillis())

// 提交保存
editor.apply()

KTX 简化写法:

sp.edit {
    putString("username", "张三")
    putBoolean("darkMode", true)
}

读取数据

val username = sp.getString("username", "默认值")
val age = sp.getInt("age", 0)
val darkMode = sp.getBoolean("darkMode", false)

每个 getXxx 方法第二个参数是默认值:如果 key 不存在,返回这个值。

commit vs apply

提交保存有两种方式:

方法执行方式返回值适用场景
apply()异步,后台写文件日常使用(推荐)
commit()同步,阻塞当前线程Boolean(是否成功)需要确认写入成功时
// 推荐:异步,不阻塞 UI
editor.apply()

// 同步:阻塞直到写完,但能知道是否成功
val success = editor.commit()
Warning
  • 日常用 apply(),它是异步的不阻塞 UI 线程。commit() 同步写文件会卡 UI,除非你需要立刻确认保存成功(比如关键数据写入前),否则别用。但 apply() 的缺点是你不知道是否保存成功,而且系统在 apply() 后立刻关机可能丢失数据。

删除数据

sp.edit {
    remove("username")   // 删除单个 key
    // clear()           // 清空所有数据
}

判断 key 是否存在

if (sp.contains("username")) {
    // 存在
}

注册数据变化监听

val listener = SharedPreferences.OnSharedPreferenceChangeListener { sp, key ->
    when (key) {
        "darkMode" -> {
            val darkMode = sp.getBoolean(key, false)
            // 主题变了,更新界面
        }
    }
}

sp.registerOnSharedPreferenceChangeListener(listener)

// 不用时注销
sp.unregisterOnSharedPreferenceChangeListener(listener)
Tip
  • 监听器持有 SharedPreferences 的弱引用,不会导致内存泄漏。但 Activity 销毁时仍建议注销,保持代码整洁。

SP 的局限

SharedPreferences 有几个问题:

  1. 同步读阻塞getXxx() 是同步的,首次加载时在主线程读 XML 文件。
  2. 不支持大数据:存几百个键值对以上就慢了。
  3. 类型不安全putInt 存的值用 getString 读会崩。
  4. 不支持协程:无法用协程等待写入完成。
  5. 数据可见性:SP 存的是 XML 明文文件,root 设备上可被读取。

DataStore(现代替代方案)

官方推荐用 Jetpack DataStore 替代 SharedPreferences。它解决了 SP 的上述问题:协程支持、异步非阻塞、类型安全。

添加依赖

dependencies {
    implementation("androidx.datastore:datastore-preferences:1.1.1")
}

Preferences DataStore

// 创建 DataStore
private val Context.dataStore by preferencesDataStore(name = "settings")

// 定义 key
val DARK_MODE = booleanPreferencesKey("dark_mode")
val USERNAME = stringPreferencesKey("username")

// 写入(suspend 函数,在协程里调)
suspend fun saveSettings(username: String, darkMode: Boolean) {
    context.dataStore.edit { preferences ->
        preferences[USERNAME] = username
        preferences[DARK_MODE] = darkMode
    }
}

// 读取(返回 Flow,可观察)
val darkModeFlow: Flow<Boolean> = context.dataStore.data
    .map { preferences -> preferences[DARK_MODE] ?: false }

在 Compose 中使用

@Composable
fun SettingsScreen() {
    val context = LocalContext.current
    val scope = rememberCoroutineScope()

    // 读:collectAsState 自动响应变化
    val darkMode by context.dataStore.data
        .map { it[DARK_MODE] ?: false }
        .collectAsState(initial = false)

    // 写:在协程里
    Switch(
        checked = darkMode,
        onCheckedChange = { value ->
            scope.launch {
                context.dataStore.edit { it[DARK_MODE] = value }
            }
        }
    )
}
Note
  • DataStore 有两种:Preferences DataStore(类似 SP,不预定义 schema)和 Proto DataStore(用 Protocol Buffers,类型安全更强但需要定义 schema)。日常用 Preferences DataStore 就够了,API 和 SP 类似但更现代。

SP vs DataStore 对比

特性SharedPreferencesDataStore
读写方式同步读,异步/同步写全异步(协程/Flow)
线程安全不保证保证
类型安全不安全安全
数据观察监听器回调Flow 响应式
推荐度老项目可用新项目推荐
Tip
  • 新项目直接用 DataStore。老项目如果 SP 用得不多,迁移成本不高,也建议换。SP 不是不能用,但 DataStore 在各方面都更好,特别是和协程、Compose 配合时。

小结

SharedPreferences 适合存少量键值对配置,apply() 异步写入是日常首选。但它有同步阻塞、类型不安全等局限。新项目推荐用 DataStore:全异步、协程支持、Flow 响应式,和 Compose 配合更自然。下一节学习文件存储。