Android之SharedPreferences(SP)

embedded/2024/10/21 9:55:12/

目录

  • 概念
  • 使用
    • 1.获取 SharedPreferences 实例
      • 1.1 通过 Context 获取默认的 SharedPreferences 文件
      • 1.2 通过 Activity 获取默认的 SharedPreferences 文件
      • 1.3 通过 PreferenceManager 获取默认的 SharedPreferences 文件
    • 2.存储数据
    • 3.读取数据
    • 4.删除数据
    • 5.监听数据变化
  • 使用场景
  • 注意事项
  • SharedPreferences 为什么是线程安全的
    • SharedPreferences线程安全
      • 1. 数据存储和读取的线程安全性
      • 2. 使用 apply() 方法进行异步提交
      • 3. 使用 commit() 方法进行同步提交
      • 4. 数据监听的线程安全性
    • 内部实现
    • SharedPreferences 线程安全总结
  • SharedPreferences 工具类示例

SharedPreferences 是 Android 提供的一种轻量级的数据存储方式,主要用于存储简单的键值对(key-value pairs)。它非常适合保存应用的配置信息、用户设置、应用状态等小型数据。

在 Android 中,SharedPreferences 默认情况下是进程内的,即每个进程都有自己独立的 SharedPreferences 实例

为了在多进程中可靠地共享数据,推荐使用 ContentProvider。ContentProvider 是 Android 提供的用于进程间通信的机制,可以确保数据的一致性和同步性

MMKV——基于 mmap 的高性能通用 key-value 组件

概念

  • 键值对存储:SharedPreferences 使用键值对(key-value)的方式存储数据,键是字符串,值可以是多种基本数据类型。
  • 持久化存储:存储在 SharedPreferences 中的数据会被持久化到设备的文件系统中,即使应用被关闭或设备重启,数据仍然存在。
  • 轻量级:适合存储少量的简单数据,不适合存储大量数据或复杂对象。

使用

1.获取 SharedPreferences 实例

可以通过以下几种方式获取 SharedPreferences 实例:

1.1 通过 Context 获取默认的 SharedPreferences 文件

SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);

1.2 通过 Activity 获取默认的 SharedPreferences 文件

SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);

1.3 通过 PreferenceManager 获取默认的 SharedPreferences 文件

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

2.存储数据

使用 SharedPreferences.Editor 对象来存储数据。Editor 提供了多种 put 方法来存储不同类型的数据。

SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();editor.putString("username", "JohnDoe");
editor.putInt("age", 30);
editor.putBoolean("isLoggedIn", true);// 提交更改
editor.apply(); // 或者使用 commit() 方法
  • apply()异步提交,不会阻塞主线程,推荐使用(没有返回值)。
  • commit()同步提交,返回一个布尔值表示提交是否成功(有返回值)。

3.读取数据

SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);String username = sharedPreferences.getString("username", null);
int age = sharedPreferences.getInt("age", 0);
boolean isLoggedIn = sharedPreferences.getBoolean("isLoggedIn", false);

4.删除数据

可以通过 Editor 的 remove 方法删除特定键的数据,或者使用 clear 方法删除所有数据。

SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();// 删除特定键的数据
editor.remove("username");// 删除所有数据
editor.clear();// 提交更改
editor.apply(); // 或者使用 commit() 方法

5.监听数据变化

可以通过 SharedPreferences.OnSharedPreferenceChangeListener 接口监听数据的变化。

SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {@Overridepublic void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {// 当数据发生变化时的处理逻辑if (key.equals("username")) {String newUsername = sharedPreferences.getString(key, null);// 处理新的用户名}}
};// 注册监听器
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);// 取消注册监听器
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);

使用场景

  • 用户设置:保存用户的偏好设置,如主题、通知设置等。
  • 应用状态:保存应用的状态信息,如上次登录时间、用户会话信息等。
  • 简单数据缓存:保存一些简单的临时数据,如搜索历史、用户输入等。

注意事项

  • 适用范围:SharedPreferences 适合存储少量的简单数据,不适合存储大量数据或复杂对象。
  • 线程安全:SharedPreferences 是线程安全的,可以在多个线程中安全地使用。
  • 性能:使用 apply() 方法进行异步提交,避免阻塞主线程。

SharedPreferences 为什么是线程安全的

SharedPreferences线程安全

SharedPreferences 的线程安全性主要体现在以下几个方面:

1. 数据存储和读取的线程安全性

  • 读取操作:SharedPreferences 的读取操作是线程安全的。读取数据时不会有并发问题,因为读取操作是无锁的,并且不会修改底层数据结构。
  • 写入操作:SharedPreferences 的写入操作通过 SharedPreferences.Editor 类进行。Editor 类使用内部锁机制来确保写入操作的原子性

2. 使用 apply() 方法进行异步提交

  • apply() 方法:apply() 方法在后台线程中异步提交数据,不会阻塞主线程。它通过 SharedPreferencesImpl 类的 enqueueDiskWrite 方法将写操作加入队列,并在后台线程中执行。这种方式避免了多个线程同时写入数据时的冲突

3. 使用 commit() 方法进行同步提交

  • commit() 方法:commit() 方法是同步提交数据,返回一个布尔值表示提交是否成功。它使用内部锁机制确保在提交过程中不会有其他线程进行写操作。虽然 commit() 是线程安全的,但它会阻塞调用它的线程,因此不推荐在主线程中使用。

4. 数据监听的线程安全性

  • 数据监听:SharedPreferences 提供了 registerOnSharedPreferenceChangeListener 方法来注册数据变化监听器。当数据发生变化时,所有注册的监听器会被通知。SharedPreferences 内部通过同步机制确保在通知监听器时的线程安全性。

内部实现

SharedPreferences 的线程安全性主要通过以下几个内部实现来保证:

  • 锁机制:在写入操作中使用内部锁机制(如 synchronized 关键字)来确保写操作的原子性和线程安全性。
  • 异步处理:使用 apply() 方法进行异步提交,将写操作放入队列并在后台线程中执行,避免阻塞主线程。
  • 内存缓存:SharedPreferences 使用内存缓存来存储数据,减少频繁的 I/O 操作。读取操作直接从内存缓存中获取数据,保证了高效性和线程安全性。

以下是 SharedPreferences 内部使用锁机制确保线程安全性的简化示例:

public final class SharedPreferencesImpl implements SharedPreferences {private final Object mLock = new Object();private final Map<String, Object> mMap;@Overridepublic Map<String, ?> getAll() {synchronized (mLock) {return new HashMap<>(mMap);}}@Overridepublic Editor edit() {return new EditorImpl();}public final class EditorImpl implements Editor {private final Map<String, Object> mModified;@Overridepublic Editor putString(String key, String value) {synchronized (mLock) {mModified.put(key, value);return this;}}@Overridepublic void apply() {final Runnable writeToDiskRunnable = new Runnable() {@Overridepublic void run() {synchronized (mLock) {// 将 mModified 写入磁盘}}};// 异步执行写操作new Thread(writeToDiskRunnable).start();}@Overridepublic boolean commit() {synchronized (mLock) {// 将 mModified 写入磁盘return true;}}}
}

在这个简化的示例中,mLock 用于同步访问共享资源(如 mMap 和 mModified),以确保线程安全性。

SharedPreferences 线程安全总结

SharedPreferences 的线程安全性是通过内部锁机制、异步处理和内存缓存等方式实现的。这些机制确保了在多线程环境下进行数据存储和读取操作时的安全性和高效性。

SharedPreferences 工具类示例

import android.content.Context;
import android.content.SharedPreferences;public class SharedPrefsHelper {private static final String PREF_NAME = "MyPrefs";private static SharedPrefsHelper instance;private SharedPreferences sharedPreferences;private SharedPreferences.Editor editor;private SharedPrefsHelper(Context context) {sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);editor = sharedPreferences.edit();}public static synchronized SharedPrefsHelper getInstance(Context context) {if (instance == null) {instance = new SharedPrefsHelper(context.getApplicationContext());}return instance;}// 存储字符串public void putString(String key, String value) {editor.putString(key, value);editor.apply();}// 读取字符串public String getString(String key, String defaultValue) {return sharedPreferences.getString(key, defaultValue);}// 存储整数public void putInt(String key, int value) {editor.putInt(key, value);editor.apply();}// 读取整数public int getInt(String key, int defaultValue) {return sharedPreferences.getInt(key, defaultValue);}// 存储布尔值public void putBoolean(String key, boolean value) {editor.putBoolean(key, value);editor.apply();}// 读取布尔值public boolean getBoolean(String key, boolean defaultValue) {return sharedPreferences.getBoolean(key, defaultValue);}// 存储浮点数public void putFloat(String key, float value) {editor.putFloat(key, value);editor.apply();}// 读取浮点数public float getFloat(String key, float defaultValue) {return sharedPreferences.getFloat(key, defaultValue);}// 存储长整型public void putLong(String key, long value) {editor.putLong(key, value);editor.apply();}// 读取长整型public long getLong(String key, long defaultValue) {return sharedPreferences.getLong(key, defaultValue);}// 删除特定键的数据public void remove(String key) {editor.remove(key);editor.apply();}// 清除所有数据public void clear() {editor.clear();editor.apply();}
}

在应用中使用 SharedPrefsHelper 工具类进行数据存储和读取:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 SharedPrefsHelper 实例SharedPrefsHelper sharedPrefsHelper = SharedPrefsHelper.getInstance(this);// 存储数据sharedPrefsHelper.putString("username", "Alan");sharedPrefsHelper.putInt("age", 30);sharedPrefsHelper.putBoolean("isLoggedIn", true);// 读取数据String username = sharedPrefsHelper.getString("username", "defaultName");int age = sharedPrefsHelper.getInt("age", 0);boolean isLoggedIn = sharedPrefsHelper.getBoolean("isLoggedIn", false);// 显示读取的数据Log.d("MainActivity", "Username: " + username);Log.d("MainActivity", "Age: " + age);Log.d("MainActivity", "Is Logged In: " + isLoggedIn);}
}

http://www.ppmy.cn/embedded/108843.html

相关文章

来聊聊C++中的vector

一.vector简介 vector是什么 C 中的 vector 是一种序列容器&#xff0c;它允许你在运行时动态地插入和删除元素。 vector 是基于数组的数据结构&#xff0c;但它可以自动管理内存&#xff0c;这意味着你不需要手动分配和释放内存。 与 C 数组相比&#xff0c;vector 具有更多的…

吐血整理 ChatGPT 3.5/4.0 新手使用手册~ 【2024.09.03 更新】

以前我也是通过官网使用&#xff0c;但是经常被封号&#xff0c;就非常不方便&#xff0c;后来有朋友推荐国内工具&#xff0c;用了一阵之后&#xff0c;发现&#xff1a;稳定方便&#xff0c;用着也挺好的。 最新的 GPT-4o、4o mini&#xff0c;可搭配使用~ 1、 最新模型科普&…

清洁眼镜片

经常眼镜弄脏了 怎么弄都干净不了 根本无法佩戴 影响出门时间 有时在外很尴尬 其实清洁很简单 从水龙水冲洗镜片(可附上洗手液) 然后用纸巾局部点触抹干偶尔泛起小水滴 就好

MySQL数据库(初始上)

什么是MySQL MySQL是一个客户端——服务器结构的程序&#xff0c;MySQL的服务器是真正的本体&#xff0c;负责保存和管理数据&#xff0c;数据存储在硬盘上。数据库指的是逻辑上数据的集合&#xff0c;一个MySQL服务器上可以有很多表&#xff0c;把有关连的连到一起就构成了一…

马来西亚参访团走进数字人企业世优科技,共鉴元宇宙数字创新成果

在数字化转型的浪潮中&#xff0c;全球企业正加速拥抱创新技术&#xff0c;以期在激烈的市场竞争中占据先机。 9月4日&#xff0c;马来西亚CCG集团、马来西亚TOPWORK公司、马来西亚一带一路总商会的嘉宾们齐聚一堂&#xff0c;共同参访了总部位于中国北京的世优科技公司&#…

学习计划(大三上)

第二周 总结Java并发编程的艺术 学习JVM&#xff08;博客文章&#xff09; 第三周 学习JVM&#xff08;博客文章&#xff09; 图解TCP/IP 4章 第四周 完成简历项目 学习JVM&#xff08;博客文章&#xff09; 图解TCP/IP 4章 第五周 完成简历项目 深入学习RocketMQ底层…

Java面试篇基础部分-JVM详细介绍

JVM的运行机制 JVM&#xff08;Java Virtual Machine&#xff09;是用于运行Java字节码的虚拟计算机&#xff0c;其中包括一套字节码的指令集、程序寄存器、虚拟机栈、虚拟机堆、本地方法区、垃圾回收器。JVM运行在操作系统上层&#xff0c;它不跟底层硬件直接进行交互。如下图…

| Origin绘图 |瀑布图的绘制(保姆级教程)

&#x1f411; | Origin绘图 |瀑布图的绘制&#x1f411; 文章目录 &#x1f411; | Origin绘图 |瀑布图的绘制&#x1f411;前言瀑布图简介瀑布图绘制数据导入坐标轴刻度调节调整画布大小添加颜色及设置线条为曲线坐标轴标签调节网格调节 总结 前言 感觉好久没出过关于Origin…