HarmonyOS 实战 | 数据存本地——Preferences 轻量存储入门

HarmonyOS 实战 | 数据存本地——Preferences 轻量存储入门 一、我们想解决什么问题咱们先聊个真实的场景。你打开一个阅读类 App晚上躺在床上看屏幕太亮眼睛不舒服于是你切到了深色模式。界面变成黑底白字舒服了。你翻了十来页标记了一个书签然后关掉 App 睡觉。第二天你打开同一个 App——好家伙深色模式没了又变成白晃晃的亮色主题上次看到的小说第 52 章第 7 页也不记得了又得从头翻。你是不是想骂人这是不是特别眼熟类似的场景太多了你给记事本 App 调了个字体大小下次打开又变回默认字号你设置了开启时自动刷新关掉 App 再进这个选项又取消了你输入了一个收货地址格式的偏好下次打开表单自动填充的信息全不见了你就想让某个开关保持开的状态但 App 每次打开都跟你玩失忆这些问题的本质是什么数据没有本地存下来。说得技术一点叫做没有做数据持久化。持久化这个词听起来唬人说白了就是你把一个值写进去了下次 App 打开的时候它还在那儿——就像你在冰箱里放了一瓶可乐第二天打开冰箱它还在没消失。HarmonyOS 给我们提供了好几种本地存储方案。但如果你要存的不是什么大文件、不是什么复杂的数据库只是一些小东西——比如用户偏好设置、开关状态、最近一次的操作记录——那用 Preferences 是最合适的。打个比方如果你要搬家大件家具叫搬家公司那是数据库或者文件存储干的活儿而 Preferences 就是你自己随身带的那个小背包装钥匙、钱包、手机——轻便、快速、随拿随取。Preferences 是什么它的全名叫轻量级偏好存储。你从名字就能看出来——它专门管偏好这类东西。在 HarmonyOS 里它是以 KV 对Key-Value键值对的形式来存数据的。什么叫 KV 对想象你有一个储物柜。每个柜子上面贴了个标签Key比如深色模式开关柜子里面放了对应的东西Value比如true表示开启了深色模式。你要取东西的时候只要看标签就行了不用把整个柜子翻一遍。就是这么简单。所以今天我们聊的就是怎么用 Preferences 来搞定这些小数据的本地存储问题。你不用操心什么数据库建表、什么 SQL 语句、什么文件 IO 路径——Preferences 把这些都封装好了你只需要告诉它“帮我存一下这个值和帮我取一下这个值”。二、数据模型设计在开始写代码之前咱们得先想清楚一件事我们要存哪些数据这就好比你去超市买东西之前最好列个清单——不然进去就蒙了出来发现想买的没买不需要的买了一堆。今天我们要做什么示例咱们来做个阅读设置面板的 Demo。这个面板包含以下几种设置项深色模式开关—— 用户是否启用了深色主题。这个值只有两种状态开或关。用布尔值boolean最合适。字体大小—— 用户选择的字号。可能是小“中”“大”超大这几个选项。用字符串string存最方便。上次阅读位置—— 用户上次看到哪一页。比如第 128 页。这是一个数字用 number 类型。用户昵称—— 用户在 App 里设置的自定义名称。这个是个字符串。四个设置项四种不同的数据类型刚好能覆盖日常使用的绝大多数场景。用 TypeScript 定义数据模型在 HarmonyOS 开发里我们通常用 TypeScript 的interface来定义数据结构。这就好比搭了个模板后面的数据都得按这个模板来。来看代码// 阅读设置的数据模型interfaceReadingSettings{// 深色模式开关darkMode:boolean;// 字体大小small / medium / large / xlargefontSize:string;// 上次阅读的页码lastPage:number;// 用户昵称userName:string;}这个 interface 定义出来之后它就像一张表格的表头——规定了每一列叫什么名字、是什么类型。我们的 App 在存数据、取数据的时候都会按照这个格式来对齐。你可能会问如果后面还要加别的设置项怎么办比如加个行间距或者翻页动画很简单在 interface 里加一行字段定义就行了。Preferences 的核心思想就是——你想存什么就存什么只要给每个数据起个名字Key它就能帮你管好。没有数据库那种我要先改表结构的麻烦。这就是 KV 存储的灵活之处每一对 key-value 都是独立的互不干扰。你可以先存一个键过两天再加一个新的键完全不用动之前的数据。但这里也得留个心眼虽然灵活但别滥用。Preferences 设计来存的是配置项“偏好设置这类少量数据不是说让你把整个应用的业务数据全塞进去。比如用户的一千条聊天记录就别放这里了——那得用数据库。Preferences 的定位就是那个随身小背包”不是搬家货车。三、核心设计决策好现在我们已经知道要存什么了。那接下来面临一个选择HarmonyOS 提供了好几种本地存储方案到底用哪个我把常见的三种方案拉出来对比一下这样你一眼就能看出差别。对比维度Preferences轻量存储KVStore分布式键值关系型数据库RDB数据量级小通常几百条以内中等大万条以上使用难度⭐ 极简两三个 API⭐⭐ 需要初始化⭐⭐⭐⭐ 需要建表、写 SQL是否分布式❌ 仅本地✅ 可跨设备同步❌ 仅本地适合场景用户偏好、开关状态、配置项需要多端同步的数据结构化复杂业务数据数据类型String / Number / Boolean / ArrayString / Number / Boolean强类型支持各种 SQL 类型读取性能极快内存缓存快但有同步开销中等SQL 查询开销现在说说我的选择。我选Preferences理由很简单——我们的需求恰好就落在它最擅长的区域里第一数据量很小。深色模式开没开、字体多大、上次看到第几页……这些东西加起来可能十个手指头就数得过来。你为了存这不到十个值去建一个关系型数据库的表那就像用搬家货车运一个背包的东西——不是不行但有点夸张了。第二不需要跨设备同步。咱们这个阅读设置的偏好就只在当前的手机上生效不需要说我在手机上设了深色模式平板也跟着变。KVStore 的分布式能力确实很厉害但这里有句实在话能力越强需要操的心也越多。如果你的 App 就只在单设备上跑没必要给自己加活。Preferences 一把梭就够了。第三开发效率。Preferences 的 API 设计得非常直觉化——存数据是put()取数据是get()删数据是delete()。就这么三个核心操作简单到你基本不用翻文档。相比之下关系型数据库你得先建表、再写 CRUD 的 SQL、还得处理事务……杀鸡不用牛刀对吧第四性能。Preferences 在读取数据的时候会把常用数据缓存在内存里第二次读的时候基本是毫秒级的甚至感觉不到延迟。用户每次打开 App要加载设置项的时候Preferences 几乎是秒回的体验。这叫润物细无声——用户感觉不到它在工作但每次体验都很丝滑。但这里我也得说句公道话Preferences 也不是万能的。如果你的数据量大了——比如超过几百条或者单条数据特别大超过了 10KBPreferences 的性能就会开始打折。这时候就该考虑数据库了。还有Preferences 只支持基础的 KV 存储不支持复杂查询。比如说你想查所有字体设为’大’的用户那 Preferences 搞不定——它没办法像数据库那样 WHERE 一把梭。所以选型这件事没有什么最好的方案只有最合适的方案。你的需求决定了你的选择。我们今天要处理的阅读设置刚好在 Preferences 的舒适区里那我们就用它。四、完整代码实现好了理论聊完了咱们来动手。我保证这部分的代码不会多——每个代码块只展示最核心的部分加起来不超过五个代码块每个不超过五十行。先把完整的工作流程走一遍创建 Preferences → 存入数据 → 读取数据 → 删除数据。就这么四个步骤。4.1 创建 Preferences 实例首先我们要创建一个 Preferences 的实例。这个过程叫做获取 Preferences 对象——通俗说就是先打开那个存数据的小本本。import{preferences}fromkit.ArkData;import{common}fromkit.AbilityKit;// 获取上下文constcontext:common.ContextgetContext(this);// 创建一个名为 reading_prefs 的 Preferences 存储实例constprefs:preferences.Preferencesawaitpreferences.getPreferences(context,reading_prefs);这段代码是什么意思呢第一行import { preferences } from kit.ArkData——这是在导入 HarmonyOS 提供的数据管理 KitPreferences 就住在里面。第三行getContext(this)——拿到当前应用的上下文。你可以把上下文理解成应用的身份证明后面很多系统级的操作都需要用到它。Preferences 也是一样它需要知道这是哪个 App 的数据所以得先拿上下文。第四行是核心preferences.getPreferences(context, reading_prefs)——这是在告诉系统“帮我在本地创建一个名为reading_prefs的存储区域”。这个reading_prefs就像是一个文件夹的名字每个 Preferences 实例都有自己的名字。后续的读写操作都基于这个区域。值得一提的是getPreferences是异步的async所以前面加了await。它会在第一次调用时创建文件后续调用就直接读缓存——所以第二次及以后的速度非常快。4.2 写入数据实例拿到了接下来就是存数据。Preferences 的存数据操作叫put——英文里就是放进去的意思非常形象。// 写入一条数据是否使用深色模式awaitprefs.put(darkMode,true);// 写入字体大小awaitprefs.put(fontSize,medium);// 写入上次阅读位置页码awaitprefs.put(lastPage,128);// 写入用户昵称awaitprefs.put(userName,小张三);// 别忘了 flush把数据真正刷到磁盘上awaitprefs.flush();看到没就这么简单。put的第一个参数是标签Key第二个参数是值Value。你把标签贴好了东西放进去了齐活。你可能会注意到我写了好几个put最后才调了一个flush。这是 Preferences 的一个设计特点写操作默认是先缓存在内存里的就像你把东西先放在了桌面上还没有收到抽屉里。调了flush()之后内存里的数据才会真正写到磁盘上确保 App 关了也不会丢。为什么不每次put完都自动flush因为磁盘读写比内存慢得多。如果用户连续修改十个偏好设置每次都刷到磁盘那就多浪费了九次 IO 操作。Preferences 的做法是让开发者自己决定什么时候一次性刷下去——这是一个性能取舍。当然如果你忘记了调flush而 App 突然崩溃了那未刷盘的数据就会丢失。所以记得改完设置了就调一次flush。从 API 12 开始Preferences 也支持了不带flush的自动刷盘模式通过put时传入特定参数可以自动持久化但为了更安全的习惯手动flush仍然是我推荐的写法——你能掌控数据什么时候落盘。4.3 读取数据存完了怎么取出来用get。// 读取深色模式开关默认值设为 falseconstisDarkMode:booleanawaitprefs.get(darkMode,false);// 读取字体大小默认值设为 mediumconstfontSize:stringawaitprefs.get(fontSize,medium);// 读取上次阅读页码默认值设为 1constlastPage:numberawaitprefs.get(lastPage,1);// 读取用户昵称默认值设为空字符串constuserName:stringawaitprefs.get(userName,);console.info(深色模式isDarkMode);console.info(字体大小fontSize);console.info(上次看到第lastPage页);console.info(用户昵称userName);get也是两个参数第一个是 Key你要取什么第二个是默认值。这个默认值很关键。你想如果用户是第一次打开 App之前根本没存过任何数据那get(darkMode)应该返回什么nullundefined还是 falsePreferences 的做法是让你提供一个如果没存过就返回这个的备用值。这就是第二个参数的作用。这么做有一个好处你的代码里不用写大量的空值判断。默认值体系保证了返回值永远是有效数据——如果用户没设过那就走默认的。对用户来说App 打开就有合理的默认配置体验很流畅。这里有个小细节get方法的返回值类型需要和默认值的类型匹配。也就是说prefs.get(darkMode, false)的时候默认值传了falseboolean那返回的就是 boolean 类型。如果你传prefs.get(darkMode, false)默认值变成了字符串那返回类型就是 string。所以写的时候要注意类型一致性。4.4 删除单条与清空有时候用户想把某个设置恢复到默认状态——比如重置字体大小。这时候就需要删除数据了。// 删除单条数据awaitprefs.delete(lastPage);awaitprefs.flush();// 或者整个清空——就像恢复出厂设置awaitprefs.clear();awaitprefs.flush();delete是删一条clear是把整个reading_prefs里的数据全清空。用哪个取决于你的场景——是想删掉一个设置还是把用户的所有偏好恢复默认。HarmonyOS 还有一个跟 Preferences 配合得很好的机制持久化订阅。你可以监听某个 Key 的变化比如当用户改了深色模式你可以自动更新 UIprefs.on(change,(key:string){if(keydarkMode){// 自动切换主题applyTheme(prefs.get(darkMode,false));}});但要注意这个监听器是比较轻量的通知机制不是事件总线——别在上面挂太多复杂逻辑。而且从 API 12 开始建议用PreferencesChangeCallback配合on(multiSettingsChange)来批量处理变更性能和可维护性更好。这里先提一句不展开后续深入聊监听机制的时候再说。4.5 完整的使用函数最后我把上面这些操作整合成一个完整的使用示例方便你直接复制过去跑import{preferences}fromkit.ArkData;import{common}fromkit.AbilityKit;exportclassSettingsManager{privateprefs:preferences.Preferences|nullnull;privatereadonlystoreNamereading_prefs;// 初始化 Preferencesasyncinit(context:common.Context):Promisevoid{this.prefsawaitpreferences.getPreferences(context,this.storeName);console.info(Preferences 初始化完成);}// 保存所有阅读设置asyncsaveSettings(settings:ReadingSettings):Promisevoid{if(!this.prefs)thrownewError(未初始化);awaitthis.prefs.put(darkMode,settings.darkMode);awaitthis.prefs.put(fontSize,settings.fontSize);awaitthis.prefs.put(lastPage,settings.lastPage);awaitthis.prefs.put(userName,settings.userName);awaitthis.prefs.flush();console.info(设置已保存);}// 读取所有阅读设置asyncloadSettings():PromiseReadingSettings{if(!this.prefs)thrownewError(未初始化);return{darkMode:awaitthis.prefs.get(darkMode,false),fontSize:awaitthis.prefs.get(fontSize,medium),lastPage:awaitthis.prefs.get(lastPage,1),userName:awaitthis.prefs.get(userName,),};}// 重置指定设置删掉对应 KeyasyncresetSetting(key:string):Promisevoid{if(!this.prefs)thrownewError(未初始化);awaitthis.prefs.delete(key);awaitthis.prefs.flush();}}这个SettingsManager你可以理解成一个管家——它帮你统一管理所有跟设置相关的存取操作。init负责启动并连接数据源saveSettings负责批量保存loadSettings负责批量读取resetSetting负责删除某一条。麻雀虽小五脏俱全。你看没有任何复杂的 SQL 语句没有建表的过程没有事务管理——就是put、get、delete、flush四个操作来回组合。这就是 Preferences 的轻量所在。五、深度技术原理很多文章写到上面那一步就结束了——代码给你了你用就完了。但既然是揉碎了讲咱们还得往深挖一层让你不光会用还知道它背后是怎么工作的。Preferences 的内部结构Preferences 在底层到底是怎么存数据的它在文件系统里是一份 XML 文件。没错就是那种带着tag和/tag的 XML 格式。每个 Key 对应一个 XML 节点Value 编码在里面。不过这些都是系统帮你打理好的你不需要自己去碰这个文件也不需要关心它的格式——但你得知道有这么个东西存在这样你才能理解它的一些行为。比如Preferences 不擅长存大量数据为什么因为这个 XML 文件每次flush的时候都是全量写入的——不是说只修改了一个 key就只改那一行而是把整个文件重新写一遍。如果你的数据量大了几百个 key 或者单条数据很大磁盘 IO 开销就会线性增长。再比如说为什么 Preferences 的读取很快因为它有个内存缓存层。初始化的时候它会把这个 XML 文件整个读到内存里变成一个 Map映射表。后续的get操作根本不碰磁盘直接从内存 Map 里取所以速度特别快。这个设计其实挺巧妙的写入走先记内存 → 后统一刷盘的延迟写策略读取走一次加载 → 全程内存访问的路子。读多写少完美匹配。与其他存储方案的数据对比咱们来做一个非常接地气的性能对比。假如你的 App 里有 50 条配置项每条数据平均大小 256 字节总数据量大约只有 12.5KB——还不到一张普通自拍照片的十分之一。这种量级下Preferences 的初始化加载时间基本在 5ms 以内单次get操作在 0.1ms 级别。如果你用数据库来存同样这 50 条数据光是建立数据库连接、建表、写 SQL启动时间就要多费几十甚至上百毫秒。为了 50 条配置不值得。但反过来如果你的数据量到了 10 万条Preferences 就会变得很吃力——因为每次flush都是全量写10 万条数据序列化成 XML 再写磁盘那延迟就不是毫秒级了可能是几百毫秒甚至秒级了。而且全部加载到内存也占空间。到那个量级数据库才是正解。所以记住这个判断尺度50 条以内无脑 Preferences500 条以上慎重上千条换数据库。中间带区域不绝对得结合单条数据大小和读写频率判断。线程安全与并发Preferences 在 HarmonyOS 里设计为线程安全的。也就是说你不用担心多个异步任务同时读写同一个 Preferences 实例会导致数据错乱。系统内部做了锁机制来保证一致性。但这不代表你完全不用操心。一个常见的坑是不要同时创建多个指向同一个存储名字的 Preferences 实例。比如你在 A 页面调了getPreferences(context, reading_prefs)又在 B 页面调了同样名字的getPreferences(context, reading_prefs)——虽然系统会尽量复用同一个实例但在某些极端并发场景下还是可能出现不一致的情况。最佳实践是同一个存储名字在整个应用生命周期里只初始化一次全局共享。上面代码里写的SettingsManager设计成了单例的使用模式——通过类来封装外部只调用它的方法不直接创建第二个 Preferences 实例。这样做的好处是所有数据访问都通过同一个管家不会出现左手不知道右手做了什么的问题。Preferences 的生命周期Preferences 的数据会跟随应用的生命周期。简单来说应用卸载 → Preferences 数据被清除应用清除缓存 → Preferences 数据可能被清除应用更新覆盖安装 → Preferences 数据通常保留系统设置中清除应用数据 → Preferences 数据被清除这一点在设计时要留意。如果你的 App 存储了用户是否已经完成新手引导这个标记——当 App 更新后Preferences 数据在大多数情况下是保留的所以用户不会重新走一遍新手引导。但如果你需要每次更新都重置某些设置那你就得在更新后的首次启动时手动去删除或重置那些 key。HarmonyOS 从 API 10 开始提供了preferences.removePreferencesFromCache(context, name)方法你可以在特定时机主动释放 Preferences 占用的内存——比如在不需要某个存储实例的时候调这个方法来释放内存资源。对于长时间运行的后台 Service这是个有用的优化点。数据隐私与安全Preferences 的数据是存储在应用私有目录下的。这意味着其他应用无法访问你的 Preferences 数据。在 HarmonyOS 的安全模型下每个应用有自己独立的沙箱环境Preferences 文件就在这个沙箱里。但有一个注意事项Preferences 不是加密存储的。如果你存的是明文密码、密钥、Token 等敏感信息Preferences 不合适——因为 XML 文件里就是原始文本。敏感信息请用 HarmonyOS 的安全存储方案如kit.ArkData里提供的加密存储能力或者使用密钥管理服务。所以在设计数据模型的时候建议做个简单的脱敏检查问自己一句“这个值如果被别人看到了会有什么问题” 如果是深色模式是否开启、“字体大小这类信息随便看没问题。如果是用户自动登录的 Token”那就得用加密方案了。总结一下 Preferences 的核心原理数据是 XML 文件存储在应用私有沙箱目录下加载时全量读入内存后续读取不碰磁盘——读取接近于白嫖写入走内存缓存 flush 触发全量刷盘——小数据高效大数据吃力线程安全——多任务并发不用太担心但注意实例唯一性非加密——敏感信息另寻他法这套设计思路其实在移动开发领域不是 HarmonyOS 首创的——Android 有 SharedPreferences本质上和这个如出一辙。但 HarmonyOS 在这个基础上做了一些优化比如 API 更简洁、类型安全更好、异步模型更一致。一句话总结站在前人的肩膀上做了一些更适合鸿蒙生态的调整。六、常见问题解答Q1: Preferences 能存多少条数据A: 官方没有硬性限制条数但工程上建议控制在 200 条以内单条数据大小不超过 1MB整体数据量不超过 10MB。原因就是上文说的——flush 是全量写入数据多了写入性能会明显下降。超过这个量级建议上数据库。Q2: 我能不能存一个对象Object进去A: 可以直接存数字、字符串、布尔值、数组这些基础类型。如果要存复杂的嵌套对象建议用JSON.stringify()转成字符串再存读的时候用JSON.parse()转回来。比如constuserConfig{theme:dark,lineSpacing:1.5};awaitprefs.put(userConfig,JSON.stringify(userConfig));constrawawaitprefs.get(userConfig,{});constconfigJSON.parse(raw);这是一种很常见的曲线救国方案。有约 5-10% 的小性能开销但对于配置项完全够用。Q3: flush 忘记调了会发生什么A: 这是个好问题。如果你调了put但没调flush而 App 在这个间隙被系统杀死了比如后台被回收、崩溃了那内存里缓存的修改就会丢失。所以先 put 后 flush应该形成肌肉记忆。不过从 API 12 开始Preferences 也提供了自动刷盘的选项但手动 flush 更可控。Q4: 如果我同时在多个页面读写同一个 Preferences 会冲突吗A: 线程安全层面系统做了锁保护不会出现数据错乱。但可能出现脏读——比如 A 页面写入了一个值但还没 flushB 页面读到的还是旧值。通常影响不大因为 flush 很快。如果你的场景对实时一致性要求高比如 A 写入后 B 必须立刻读到那可以考虑在读取前主动调一次flush。Q5: Preferences 和数据库可以混用吗A: 当然可以而且这是很常见的设计。比如一个笔记 App笔记的正文和列表用数据库存数据量大、需要搜索而用户偏好的主题、字体、排序方式用 Preferences 存。两者各司其职互不干扰。这也是架构设计里使用合适的工具做合适的事的体现。Q6: 我的 Preferences 文件在哪能自己手动改吗A: 在应用沙箱目录下的某个路径具体是由系统管理的。不建议也不应该手动去修改这个文件——首先你还需要设备 root 权限才能访问到沙箱目录其次手动修改可能会破坏文件格式导致整个 Preferences 实例加载失败。所有的读写操作通过 API 来完成就好别去动那个文件。Q7: Preferences 能存图片或者文件吗A: 不能。Preferences 只能存字符串、数字整数和小数、布尔值这些原子类型。如果你想存一张图片、一个 PDF、一段录音那就不是 Preferences 该干的活了——得用文件存储通过file.fs相关 API或者数据库。Preferences 的定位非常明确小数据、简单值、键值对。别让它干超出能力范围的事。七、运行效果下面我们用 ASCII 字符画来模拟 App 的运行效果。想象你打开了一个阅读 App第一件事就是加载之前保存的设置当用户点击保存设置按钮时发生的事情然后第二天你再次打开 App你看从用户的角度来说一切都很自然——我昨天怎么设置的今天打开还那样。这种体验的好是用户说不出来但能感受到的。那些让你每次都要重新设一遍的 App为什么觉得不好用就是因为没有做数据持久化。八、扩展方向到这儿Preferences 的核心内容基本都讲完了。但学习和实践的边界不止于此我列几个可以继续深入的方向给你一些灵感。1. 与 UI 状态管理联动Preferences 存的只是数据怎么把数据和 UI 连接起来在 HarmonyOS 开发里你可以结合State和Link装饰器让数据变化自动刷新界面。更进阶一点可以用AppStorage配合 Preferences 做全局状态同步——AppStorage是 ArkUI 提供的应用级状态存储它和 Preferences 的区别是AppStorage 只在运行时存在App 一关就没了Preferences 是持久化的。两者结合的方式是App 启动时从 Preferences 读数据写入 AppStorage用户修改时AppStorage 变 → 同步到 Preferences → flush。2. 多用户场景的隔离如果你的 App 支持多账号切换那每个账号的偏好设置不应该混在一起。可以在 Preferences 的存储名字上做文章比如reading_prefs_user_001和reading_prefs_user_002每个用户一个独立的存储实例。切换账号的时候切换对应的 Preferences 实例就行了。3. 配合云备份Preferences 数据存在本地但如果用户换手机了这些偏好就丢了。想要更好的体验可以考虑把 Preferences 中的数据同步到云端——在用户切换设备的时候从云端拉取偏好设置恢复到本地。HarmonyOS 的kit.ArkData提供了 KVStore 的分布式能力如果你真的需要多端同步可以从 Preferences 平滑迁移到 KVStore——因为它们的数据模型键值对是一样的迁移成本不高。4. 性能监控在开发阶段可以在 Preferences 的读写操作前后加上时间戳统计每次操作的耗时。如果在真机测试时发现flush耗时超过 100ms那就该考虑是不是 Preferences 里数据太多了或者检查单条数据是不是太大了。保持对性能的敏感是做好轻量的关键。5. 监听数据变更做更丰富的业务逻辑前面提到了on(change)的用法但这个能力的想象空间其实挺大的。举个例子你的阅读 App 有个每日阅读提醒功能要求在字体大小改到超大时弹出提示考虑减少阅读时间以保护视力。通过 Preferences 的变更监听你可以在fontSize改变的那一刻触发这个逻辑——不需要轮询、不需要手动判断。6. 多 Process 并发写入如果你的 App 使用了多进程架构比如在主进程和后台 Service 进程里分别读写 Preferences需要注意不同进程各自维护自己的 Preferences 实例不会自动同步。这种情况下建议用数据库做存储或者通过 IPC进程间通信让所有写入操作都通过主进程完成。结语聊到这里关于 Preferences 轻量存储的话题就到尾声了。你可以发现它其实没有太多花哨的东西——一个结构简单、API 极简、性能出色的本地存储方案专门处理小数据的场景。它不追求大而全而是在自己擅长的领域里做到极致。这其实也是写代码的一个道理不是每个问题都需要一个复杂的解决方案。有时候最简单直接的方案就是最好的方案。Preferences 这样的方案就像一个可靠的伙伴——平时安静地待在后台不刷存在感但每次你需要它的时候它都在那里。下次你的 App 需要存用户的偏好了记得想到它。