跟进SharedPreferences ANR的总结

本文深入分析了SharedPreferences在Android中引发ANR(应用无响应)的问题,详细解释了主线程读取SP时因文件加载耗时过长而导致的ANR原因,并提供了一种临时解决方案:在应用启动时预加载SP值,以优化后续读取性能。

ANR分析

最近也跟进了一个SharedPreferences相关的ANR,是主线程读取SP的时(首次读取某个key的值)产生了ANR。
ANR 信息如下
在这里插入图片描述
原因是:SP加载整个文件时比较耗时,导致加载的后台线程被挂起,同时就影响到了主线程的唤醒。
即之前要主线程读取某个key时主动await了,它需要SP加载整个文件的线程Notify
在这里插入图片描述

临时解决方案:
在应用启动时主动读取SP的值,提前触发整个SP文件先加载,方便后续的读取。

个人总结

在这里插入图片描述

参考文档

### SharedPreferences 使用心得与最佳实践总结 SharedPreferencesAndroid 中一种轻量级的数据存储方式,主要用于存储简单的配置信息或用户偏好设置。以下是对 SharedPreferences 的使用心得和最佳实践的总结: #### 1. **数据存储形式与适用场景** SharedPreferences 以键值对(key-value)的形式存储数据,支持的数据类型包括 `String`、`int`、`float`、`long` 和 `boolean`。其存储位置为 `/data/data/<包名>/shared_prefs`,文件格式为 XML[^3]。由于其轻量级特性,适用于存储少量、简单的配置信息,而不适合存储复杂或大量数据。 #### 2. **获取 SharedPreferences 对象** 通过 `Context` 获取 `SharedPreferences` 对象时,可以使用两种方法: - `getSharedPreferences(String name, int mode)`:指定文件名和模式获取。 - `getPreferences(int mode)`:仅限于 Activity 内部使用,无需指定文件名。 示例代码如下: ```java SharedPreferences sharedPreferences = context.getSharedPreferences("prefs_name", Context.MODE_PRIVATE); ``` #### 3. **数据的存取操作** 数据的存取需要通过 `SharedPreferences.Editor` 完成写入操作,而读取则直接通过 `SharedPreferences` 实现。 - **写入数据**: ```java SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("key", "value"); editor.apply(); // 推荐使用 apply() 而非 commit() ``` `apply()` 方法是异步执行的,性能优于 `commit()`,后者会阻塞主线程并返回布尔值结果[^2]。 - **读取数据**: ```java String value = sharedPreferences.getString("key", "default_value"); ``` #### 4. **监听数据变化** 可以通过实现 `SharedPreferences.OnSharedPreferenceChangeListener` 接口来监听数据的变化。需要注意的是,监听器只能感知到通过 `Editor` 修改的数据变化,而无法检测到文件被外部程序修改的情况[^1]。 示例代码如下: ```java sharedPreferences.registerOnSharedPreferenceChangeListener((prefs, key) -> { if ("key".equals(key)) { // 处理逻辑 } }); ``` #### 5. **线程安全问题** SharedPreferences 在单线程环境下是线程安全的,但在多线程环境中可能会出现并发问题。为了避免冲突,建议在多线程场景下使用同步机制或考虑其他更复杂的存储方案[^2]。 #### 6. **数据安全性** SharedPreferences 的默认存储模式为 `MODE_PRIVATE`,这意味着只有应用本身可以访问这些数据。如果需要更高的安全性,可以结合加密算法对存储的数据进行加密处理[^3]。 #### 7. **性能优化** - 避免频繁调用 `SharedPreferences`,可以将常用数据缓存在内存中。 - 使用 `apply()` 替代 `commit()`,减少主线程阻塞。 - 定期清理不再使用的数据,避免文件过大影响性能。 #### 8. **常见问题与解决方案** - **数据丢失**:可能由于设备恢复出厂设置或应用卸载导致。建议在关键场景下备份重要数据。 - **存储容量限制**:SharedPreferences 文件大小有限,不适合存储大量数据。可考虑使用 SQLite 或其他数据库替代[^3]。 --- ### 示例代码:完整流程演示 以下是一个完整的 SharedPreferences 使用示例: ```java // 写入数据 SharedPreferences sharedPreferences = context.getSharedPreferences("prefs_name", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("username", "JohnDoe"); editor.putInt("age", 25); editor.apply(); // 读取数据 String username = sharedPreferences.getString("username", "Unknown"); int age = sharedPreferences.getInt("age", 0); // 注册监听器 sharedPreferences.registerOnSharedPreferenceChangeListener((prefs, key) -> { if ("username".equals(key)) { System.out.println("Username changed to: " + prefs.getString(key, "")); } }); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值