SharedPreferences使用及原理

这篇具有很好参考价值的文章主要介绍了SharedPreferences使用及原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、SharedPreferences介绍

SharedPreferences 类提供了一个通用框架,以便您能够保存和检索原始数据类型的永久性键值对。您可以使用 SharedPreferences 来保存任何原始数据:布尔值,浮点值,整型值,长整型和字符串。此数据将跨多个用户会话永久保留(即使您的应用已终止亦如此)。

SharedPreferences 使用 xml 格式为 Android 应用提供一种永久数据存贮方式,并且使用键值对的方式来存储数据的。相对于一个 Android 应用而言,目录 / data/data/your_app_package_name/shared_prefs / 下,可以被处在同一个应用中的所有 Activity 访问。Android 提供了相关的 API 来处理这些数据而不需要程序员直接操作这些文件或者考虑数据同步的问题。

二、SharedPreferences使用

SharedPreferences 本身是一个接口,程序无法直接创建 SharedPreferences 的实例,只能通过 Context 提供的 getSharedPreferences(String name,int mode) 方法来获取 SharedPreferences 的实例,其中有两个参数:第一个参数用于指定 SharedPreferences 文件的名称(格式为 xml 文件),如果该名称的文件不存在则会创建一个。第二个参数用于指定操作的模式,如下:

  • MODE_PRIVATE:默认操作模式,只有本应用程序才可以对这个 SharedPreferences 文件进行读写。
  • MODE_WORLD_READABLE:其他应用对这个 SharedPreferences 文件只能读不能修改。
  • MODE_WORLD_WRITEABLE:这个 SharedPreferences 文件能被其他的应用读写。
  • MODE_MULTI_PROCESS:这个模式在 Android2.3 之后已经弃之不用了,可以省略。

此外还得提一下 SharedPreferences.Editor 对象的一些主要方法。

  • SharedPreferences.Editor clear(): 删 SharedPreferences 中所有的数据。
  • SharedPreferences.Editor putXxx(String key , xxx value): 向 SharedPreferences 存入指定 key 对应的数据,其中 xxx 可以是 booleant 等各种基本类型数据 。
  • SharedPreferences.Editor remove(): 删除 SharedPreferences 中指定 key 对应的数据项
  • boolean commit(): Editor 编辑完成后,使用该方法同步提交修改。
  • void apply(): Editor 编辑完成后,使用该方法异步提交修改。

简单理解:在键值对中存储私有原始数据。

适用范围:用于保存少量数据,且数据的格式非常简单,如应用程序的各种配置信息。常见案例:音乐开关,用户账户设置,用户习惯设置,简单拓展:判断程序是不是第一次运行(使安卓 app 安卓后引导界面只显示一次)。

三、SharedPreferences优化

3.1 读操作的优化

每次读取一个key对应的值都要重新对文件进行一次读的操作?显然需要尽量避免笨重的I/O操作。

因此设计者针对读操作进行了简单的优化,当SharedPreferences对象第一次通过Context.getSharedPreferences()进行初始化时,对xml文件进行一次读取,并将文件内所有内容(即所有的键值对)缓到内存的一个Map中,这样,接下来所有的读操作,只需要从这个Map中取就可以了:

final class SharedPreferencesImpl implements SharedPreferences {
  private final File mFile;             // 对应的xml文件
  private Map<String, Object> mMap;     // Map中缓存了xml文件中所有的键值对
}

虽然节省了I/O的操作,但另一个视角分析,当xml中数据量过大时,这种 内存缓存机制 是否会产生 高内存占用 的风险?

这也正是很多开发者诟病SharedPreferences的原因之一,那么,从事物的两面性上来看,高内存占用 真的是设计者的问题吗?

不尽然,因为SharedPreferences的设计初衷是数据的 轻量级存储 ,对于类似应用的简单的配置项(比如一个boolean或者int类型),即使很多也并不会对内存有过高的占用;而对于复杂的数据(比如复杂对象序列化后的字符串),开发者更应该使用类似Room这样的解决方案,而非一股脑存储到SharedPreferences中。

因此,相对于「SharedPreferences会导致内存使用过高」的说法,更倾向于更客观的进行总结:

虽然 内存缓存机制 表面上看起来好像是一种 空间换时间 的权衡,实际上规避了短时间内频繁的I/O操作对性能产生的影响,而通过良好的代码规范,也能够避免该机制可能会导致内存占用过高的副作用,所以这种设计是 值得肯定 的。

3.2 写操作的优化

针对写操作,设计者同样设计了一系列的接口,以达到优化性能的目的。

我们知道对键值对进行更新是通过mSharedPreferences.edit().putString().commit()进行操作的——edit()是什么,commit()又是什么,为什么不单纯的设计初mSharedPreferences.putString()这样的接口?

设计者希望,在复杂的业务中,有时候一次操作会导致多个键值对的更新,这时,与其多次更新文件,我们更倾向将这些更新 合并到一次写操作 中,以达到性能的优化。

因此,对于SharedPreferences的写操作,设计者抽象出了一个Editor类,不管某次操作通过若干次调用putXXX()方法,更新了几个xml中的键值对,只有调用了commit()方法,最终才会真正写入文件:

// 简单的业务,一次更新一个键值对
sharedPreferences.edit().putString().commit();
 
// 复杂的业务,一次更新多个键值对,仍然只进行一次IO操作(文件的写入)
Editor editor = sharedPreferences.edit();
editor.putString();
editor.putBoolean().putInt();
editor.commit();   // commit()才会更新文件

了解到这一点应该明白,通过简单粗暴的封装,以达到类似SPUtils.putXXX()这种所谓代码量的节省,从而忽略了Editor.commit()的设计理念和使用场景,往往是不可取的,从设计上来讲,这甚至是一种 倒退 。

另外一个值得思考的角度是,本质上文件的I/O是一个非常重的操作,直接放在主线程中的commit()方法某些场景下会导致ANR(比如数据量过大),因此更合理的方式是应该将其放入子线程执行。

因此设计者还为Editor提供了一个apply()方法,用于异步执行文件数据的同步,并推荐开发者使用apply()而非commit()。

看起来Editor+apply()方法对写操作做了很大的优化,但更多的问题随之而来,比如子线程更新文件,必然会引发 线程安全问题;此外,apply()方法真的能够像我们预期的一样,能够避免ANR吗?答案是并不能。文章来源地址https://www.toymoban.com/news/detail-411722.html

到了这里,关于SharedPreferences使用及原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RPC原理介绍与使用(@RpcServiceAnnotation)

    Java RPC(Remote Procedure Call,远程过程调用)是一种用于实现分布式系统中不同节点之间通信的技术。它允许在不同的计算机或进程之间调用远程方法,就像调用本地方法一样。 ** ** 定义接口:首先,需要定义一组接口,这些接口定义了远程调用的方法和参数。接口可以使用

    2024年01月16日
    浏览(31)
  • DataX简介、部署、原理和使用介绍

    项目地址:https://github.com/alibaba/DataX 官方文档:https://github.com/alibaba/DataX/blob/master/introduction.md ​ DataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBas

    2024年02月15日
    浏览(37)
  • Spring(18) @Order注解介绍、使用、底层原理

    @Order :是 spring-core 包下的一个注解。@Order 作用是 定义 Spring IOC 容器中 Bean 的执行顺序 。 注意: Spring 的 @Order 注解或者 Ordered 接口,不决定 Bean 的加载顺序和实例化顺序,只决定 Bean 注入到 List 中的顺序。 @Order 注解接受一个整数值作为参数, 数值越小表示优先级越高 。

    2024年02月20日
    浏览(38)
  • MQTT协议原理介绍及如何使用emqx

    MQTT(Message Queuing Telemetry Transport)协议是一种轻量级的、基于发布/订阅模式的通信协议。它最初由IBM开发,用于在低带宽和不稳定的网络环境中传输小型数据包。MQTT协议被广泛应用于物联网(IoT)领域,例如传感器数据采集、远程监控和控制等。 MQTT协议使用了一种异步的、

    2024年02月12日
    浏览(38)
  • 【AIGC】【AI绘画】controlNet介绍(原理+使用)

    下载安装:建议下载V1.1版本 论文:https://arxiv.org/pdf/2302.05543.pdf 下载ControlNet仓库 切换到ControlNet主目录 创建名为control的conda虚拟环境并安装依赖 激活名为control的虚拟环境 所有模型和检测器都可以从 Hugging Face页面下载。确保 SD 模型放在“ControlNet/models”中 , 检测器放在“

    2024年02月08日
    浏览(43)
  • Python原型模式介绍、使用;浅拷贝/深拷贝原理

            1. 概念 原型模式是一种创建型设计模式,它通过复制(克隆)现有对象来创建新对象。这样可以避免使用复杂的构造函数来创建对象,提高程序的性能和可维护性。         2. 功能 原型模式的功能是通过复制现有对象来创建新对象,从而提高程序的性能和可维护性

    2024年02月15日
    浏览(39)
  • TIDB简介及TIDB部署、原理和使用介绍

    数据库分类 ​ 介绍TiDB数据库之前,先引入使用场景。如今的数据库种类繁多,RDBMS(关系型数据库)、NoSQL(Not Only SQL)、NewSQL,在数据库领域均有一席之地,可谓百家争鸣之势。那么我们为什么要学习使用TiDB呢?接下来就从我们最熟悉的MySQL的使用说起。 MySQL痛点 ​ 假设

    2023年04月20日
    浏览(30)
  • Maven介绍_下载_安装_使用_原理

    Maven的本质是一个项目管理工具,将项目开发中和管理过程抽象成一个项目对象模型 —POM POM:Project Object Model --即项目对象模型 项目构建:提供标准的,跨平台的自动化项目构建方式 依赖管理:方便快捷的管理项目依赖的资源lar包,避免资源之间的版本冲突问题 统一开发结

    2024年02月12日
    浏览(40)
  • 性能优化:如何彻底解决SharedPreferences造成的卡顿

    在上线 ANR 监控平台后,线上收集到了较多的ANR日志 ,从火焰图信息上看,函数阻塞在了QueuedWork 相关函数上 ,本文主要介绍的这一现象的原因以及如何解决这一问题。 本文介绍的解决方案,已放到github 上https://github.com/Knight-ZXW/SpWaitKiller , 供参考实现 首先简单介绍下 Queue

    2024年02月16日
    浏览(36)
  • android SharedPreferences 手机保存数据的简单方法

    import java.lang.reflect.Method; import java.util.Map; import android.content.Context; import android.content.SharedPreferences; public class SharedPreferencesManager { /** 保存在手机里面的文件名 */ // public static String FILE_NAME = “hs_eba_sharedata”; public static String SPLASH_KEY = “splash_key”; public static String EXCHANGESTATE =“

    2024年04月17日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包