SharedPreferences:是什么、Android键值存储

作者: IT Sectr 发布日期: 2026-03-12 阅读时间: 9 分钟

SharedPreferences是Android中的键值数据存储,用于保存简单的应用程序设置和配置。数据以XML文件形式存储在设备上,只能在创建它的应用程序内部访问。根据官方文档 Android Developers, 2025SharedPreferences支持存储原始类型:String、Int、Boolean、Float、Long和Set<String>。这是保存少量用户设置的最简单、最快的解决方案,无需SQL查询或直接与文件系统交互。

要点

  • SharedPreferences — Android键值存储,用于在XML文件中保存简单的应用程序设置。
  • 支持五种数据类型:String、Int、Boolean、Float、Long和Set<String>。
  • 支持同步(get)和异步(apply)写入操作并保存到磁盘。
  • 数据根据文件名和访问模式(PRIVATE、MULTI_PROCESS)进行隔离。
  • 对于大量数据,Google建议使用DataStore或Room而不是SharedPreferences。

什么是SharedPreferences?

SharedPreferences是Android内置的机制,用于在设备内部存储的XML文件中保存键值对。它从API Level 1开始可用,不需要连接额外的库。主要用途是保存用户设置、界面状态、首次启动标志以及其他不需要结构化数据库的简单数据。

每个SharedPreferences文件都与特定的名称和访问模式相关联。默认使用Context.MODE_PRIVATE模式,该模式将文件访问限制为仅当前应用程序。以前Android支持MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE模式,但从API Level 17开始它们被声明为已弃用,并在Android 7.0(API 24)中出于安全原因被完全删除。

尽管简单,SharedPreferences被数百万Android应用程序使用。根据Google的数据,Google Play上发布的应用程序中超过90%使用SharedPreferences来存储设置。然而,对于复杂场景(大量数据、类型安全、异步),Google推荐更现代的解决方案,例如来自Android Jetpack库的Preferences DataStore。

存储格式:设备上的XML

物理上,SharedPreferences以XML文件形式存储在应用程序目录中:/data/data/{package_name}/shared_prefs/{file_name}.xml。文件包含根元素<map>以及根据存储值类型而定的子元素<string>、<int>、<boolean>、<float>和<long>。文件大小没有限制,但对于大量数据(超过100 KB),读写性能开始显著下降。

SharedPreferences文件默认不加密。数据以明文形式存储在设备的文件系统中。对于存储敏感数据(令牌、密码),建议使用AndroidX Security库中的EncryptedSharedPreferences,它会使用AES256-GCM自动加密键和值。

SharedPreferences在Android中如何工作

SharedPreferences基于内存缓存并定期同步到磁盘的原理工作。首次访问文件时(通过getSharedPreferences),Android将XML文件加载到RAM中并将其解析为Map对象。所有后续读取操作都从内存中执行,无需重新从磁盘读取。这确保了数据的高速访问。

写入操作使用Editor — 一个内部更改缓冲区。当开发者调用putString或putBoolean时,更改将保存在内存中的Editor对象中。实际的磁盘写入发生在调用commit(同步)或apply(异步)方法时。在调用这些方法之前,数据不会被保存,如果应用程序意外终止,更改可能会丢失。

访问模式和上下文

获取SharedPreferences实例使用两种方法:getPreferences和getSharedPreferences。第一种仅在Activity内部可用,并创建以Activity命名的文件。第二种更灵活,接受文件名和访问模式,并可从任何上下文(Application、Activity、Service)访问。建议使用getSharedPreferences,文件名与应用程序的模块或功能相对应。

kotlin
// 获取SharedPreferences
val prefs = context.getSharedPreferences(
    "user_settings", Context.MODE_PRIVATE
)

// 写入数据
with(prefs.edit()) {
    putString("username", "安娜")
    putInt("age", 28)
    putBoolean("isLoggedIn", true)
    apply()
}

// 读取数据
val username = prefs.getString("username", "")
val age = prefs.getInt("age", 0)
val isLoggedIn = prefs.getBoolean("isLoggedIn", false)

使用MODE_MULTI_PROCESS(已弃用)时,SharedPreferences会在进程之间同步。然而,这种同步不保证原子性,Google建议避免在multi-process场景中使用SharedPreferences。对于这种情况,最好使用ContentProvider、具有进程间访问的Room或DataStore。

SharedPreferences的主要方法

SharedPreferences提供了一组按键读取数据的方法和用于写入的Editor接口。每个读取方法接受两个参数:键和默认值(如果未找到键则返回)。默认值也决定了返回值的类型:getString返回String,getInt返回Int,依此类推。

读取方法写入方法数据类型
getStringputStringString
getIntputIntInt
getBooleanputBooleanBoolean
getFloatputFloatFloat
getLongputLongLong
getStringSetputStringSetSet<String>

Editor和apply与commit

Editor — SharedPreferences的内部对象,在缓冲区中收集更改。在进行所有更改后,开发者调用commit()(同步写入)或apply()(异步写入)。区别至关重要:commit阻塞当前线程直到完全写入磁盘并返回boolean(成功/失败),而apply在后台线程中执行写入并立即返回控制权,但不返回结果。

在所有不需要知道写入结果的情况下,建议使用apply而不是commit。apply更快且不会阻塞UI线程。commit仅在需要知道数据是否成功保存或在使用multi-process模式时才应使用。对于删除单个键,使用remove方法;对于完全清除,使用clear。所有删除操作也通过Editor执行。

kotlin
// 多次更改 - 一次apply
prefs.edit {
    putString("theme", "dark")
    putBoolean("notifications", false)
    remove("old_key")
}

// 值更改监听器
prefs.registerOnSharedPreferenceChangeListener { prefs, key ->
    Log.d("TAG", "键已更改:$key")
}

从Android 12(API 31)开始,SharedPreferences增加了对registerOnSharedPreferenceChangeListener的支持,通过Lifecycle自动取消注册。这有助于避免与遗忘的监听器相关的内存泄漏。在较旧版本中,开发者必须在组件的onDestroy或onStop中手动调用unregisterOnSharedPreferenceChangeListener。

SharedPreferences与存储替代方案

尽管广泛使用,SharedPreferences并不是Android中所有数据存储场景的通用解决方案。根据数据量、类型安全和性能要求,Google推荐包含在Android Jetpack和标准Android库中的各种替代方案。

解决方案何时使用缺点
SharedPreferences小型设置(最多100个键)没有类型安全,同步读取
DataStore中等复杂度的设置,使用协程不支持API 14以下版本
Room结构化数据和列表对于3-5个设置来说过于复杂
EncryptedSharedPreferences敏感数据和令牌依赖AndroidX Security

DataStore — 现代替代方案

DataStore — 一个Android Jetpack库,由Google作为SharedPreferences的替代品推出。它提供两种变体:Preferences DataStore(键值,如SharedPreferences)和Proto DataStore(通过Protocol Buffers的类型化存储)。DataStore使用协程和Flow进行异步工作,保证类型安全,并自动处理版本迁移。Google推荐所有新项目使用DataStore。

DataStore的主要优势是API级别的异步性。所有读取操作都返回Flow,写入操作是suspend函数。这完全消除了SharedPreferences同步读取时可能出现的UI线程阻塞。此外,DataStore保证数据一致性:写入在事务中执行,如果失败,所有更改都将回滚。

在应用程序中使用SharedPreferences的示例

让我们看一个实际示例:Android应用程序中的主题设置(亮色/暗色/系统)。用户选择主题,选择保存在SharedPreferences中。在后续应用程序启动时,主题从保存的设置中恢复。对于响应式界面更新,通过SharedPreferences.OnSharedPreferenceChangeListener观察更改。

保存用户设置

我们将创建ThemePreferences类,它封装了与SharedPreferences相关的所有主题工作。该类提供getTheme(读取)、setTheme(写入)和observeTheme(观察)方法。设置文件名称为"app_preferences",使用MODE_PRIVATE模式。为方便起见,键作为常量放在companion object中。

kotlin
class ThemePreferences(context: Context) {
    companion object {
        private const val PREF_NAME = "app_preferences"
        private const val KEY_THEME = "theme_mode"
        const val THEME_LIGHT = "light"
        const val THEME_DARK = "dark"
        const val THEME_SYSTEM = "system"
    }

    private val prefs = context
        .getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)

    fun getTheme(): String =
        prefs.getString(KEY_THEME, THEME_SYSTEM) ?: THEME_SYSTEM

    fun setTheme(theme: String) {
        prefs.edit { putString(KEY_THEME, theme) }
    }

    fun observeTheme(callback: (String) -> Unit) {
        prefs.registerOnSharedPreferenceChangeListener { _, key ->
            if (key == KEY_THEME) {
                callback.invoke(getTheme())
            }
        }
    }
}

在Activity或Fragment中,通过应用程序上下文获取ThemePreferences实例。初始化时调用getTheme设置当前主题。当用户选择新主题时,调用setTheme,通过observeTheme界面无需重启Activity即可更新。重要的是不要忘记在onDestroy中取消注册监听器以防止内存泄漏,特别是在配置更改时重新创建Activity的情况下。

对于最低目标版本为Android 12+的应用程序,建议使用registerOnSharedPreferenceChangeListener与LifecycleObserver结合。这会在组件生命周期变化时自动管理注册和取消注册。对于较旧版本,注册和取消注册必须手动管理,这是使用SharedPreferences的生产应用程序中常见的错误来源。

常见问题

可以在SharedPreferences中存储对象吗?

SharedPreferences直接只支持原始类型和Set<String>。要存储对象,需要通过Gson或Moshi将它们序列化为JSON字符串,通过putString保存,并在读取时反序列化。对于具有大量字段的复杂对象,建议使用Room而不是带有JSON序列化的SharedPreferences。

SharedPreferences是线程安全的吗?

是的,SharedPreferences是线程安全的。所有读写操作都在SharedPreferences对象及其Editor级别同步。然而,在使用multi-process模式时,不保证同步。对于单个应用程序中来自多个线程的并发访问,SharedPreferences在没有额外锁的情况下是安全的。

如何清除所有SharedPreferences数据?

要完全清除SharedPreferences中的所有数据,在Editor上调用clear()方法并通过apply应用更改。如果需要删除XML文件本身,在上下文上使用deleteSharedPreferences(name)。通过设置→应用程序→清除数据来清除应用程序数据也会删除所有SharedPreferences文件。

SharedPreferences还是DataStore:如何选择?

对于新项目,Google推荐DataStore作为SharedPreferences的替代品。DataStore提供使用协程的异步工作、类型安全(Proto DataStore)和自动迁移。只有在最低版本低于API 14的项目或需要快速集成且无需额外依赖时,才应选择SharedPreferences。

如何加密SharedPreferences中的数据?

要加密数据,请使用AndroidX Security库中的EncryptedSharedPreferences。它使用AES-256 GCM自动加密键和值。设置过程非常简单:将getSharedPreferences替换为EncryptedSharedPreferences.create,并指定来自Android Keystore的主密钥。

总结

  • SharedPreferences — Android内置的键值存储,用于以XML格式保存简单的应用程序设置。
  • 支持六种数据类型:String、Int、Boolean、Float、Long和Set<String>,并指定默认值。
  • 读取操作从内存(缓存)执行,写入 — 通过Editor使用同步commit或异步apply。
  • 数据根据文件名和MODE_PRIVATE模式隔离,仅在创建它的应用程序内部可访问。
  • 对于敏感数据的存储,使用带有AES-256加密的EncryptedSharedPreferences
  • 对于新项目,Google推荐DataStore作为使用协程和Flow的现代异步替代方案。
  • SharedPreferences仍然是无需额外依赖即可快速保存5-50个简单设置的最佳选择。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读