在应用程序间及与用户的通信交互过程中,会产生并传递一系列数据。针对这些数据,有部分是只在应用程序中使用的缓存数据,还有一部分是在不同位置多次或长时间使用的持久化数据。

对于缓存数据来说,通常以代码中定义局部变量或全局变量的方式访问使用,这种使用方式伴随在编程的整个过程中;而持久化数据,则需要以特定的文件格式保存在系统硬盘中,使用系统提供的框架方法来访问使用。而根据要持久化保存数据的复杂程度不同,分别有轻量级SharedPreferences,数据库SQLiteOpenHelper或其封装的Room,以及二进制访问的文件File这三种方式。本文主要对持久化数据的几种不同类型简做介绍。

轻量级SharedPreferences

对于轻量级的键值对数据,可以使用android.content.SharedPreferences共享选项接口实现的相关类以持久化保存。

SharedPreferences形式保存的数据,将会以 key-value 键值对的形式,基于 xml 格式的文件保存在当前应用的内部存储空间中。这种应用程序的内部存储空间中的文件,只允许其所属应用程序读写。而当应用程序卸载后,或通过 系统桌面 - 设置 - 应用管理 - 当前应用程序 - 应用数据 - 清除数据 系列操作后,其内部存储空间也将被清空。这在一定程度上保证了内部存储空间的数据安全。

创建文件

在AndroidSDK中已经定义SharedPreferencesImpl类作为SharedPreferences接口的实现类。

对于SharedPreferences接口的实例化对象,在可以访问上下文环境Context对象的地方,可通过调用Context对象的getSharedPreferences(String name, int mode)方法获取。其对应的 xml 格式文件将在当前应用程序整个生命周期过程中读写访问。

或者也可以在Activity界面中,调用Activity对象的getPreferences(int mode)方法获取,其对应的 xml 文件只在当前界面生命周期中读写访问。

getSharedPreferences(String name, int mode)方法中,

参数 name 指定存储当前数据的 xml 格式文件的文件名,其值可由开发者定义。

参数 mode 为文件的打开方式,其值通常为仅允许当前应用程序访问该文件的Context.MODE_PRIVATE=0;在Android6.0即API23之前,该值也可以为允许多进程读写同步的Context.MODE_MULTI_PROCESS=4,然而该模式下会出现各种异常问题,故此版本后被弃用;在Android4.2即API17之前,mode 值也可以为允许其他应用程序读该文件的Context.MODE_WORLD_READABLE=1,和允许其他应用程序写该文件的Context.MODE_WORLD_WRITEABLE=2,但这两个值均不能保证当前应用程序的数据安全性,故此版本之后被弃用。

另外,如果看不惯系统定义的SharedPreferencesImpl实现类,开发时完全可以自定义一个SharedPreferences接口的实现类,在使用context.getSharedPreferences(String name, int mode)获取实例化对象的位置替换为自定义的实现类对象即可。

总之,在获取SharedPreferences对象时,系统检测当前应用程序内部存储空间中是否有指定 namexml 格式文件,若没有将会先创建。之后系统便会打开该文件,通过SharedPreferences对象就可以读写该文件了。

数据写入文件

如果想向创建的SharedPreferences对象所在文件中写入数据,只需要调用该对象的edit()方法,以获取android.content.SharedPreferences.Editor接口类型的对象。

类似于界面间交互使用的Intent意图中传递的数据方式,在SharedPreferences.Editor接口对象中,可以使用putBoolean(String key, boolean value)设置boolean类型的数据,putFloat(String key, float value)设置float类型的数据,putStringSet(String key, Set<String> values)设置String集合的数据等。这一系列的设置方法,其参数一 key 都是作为SharedPreferences文件中唯一的String类型的值,以标记当前数据;其参数二 value 则是要持久化保存的数据值。

另外,在SharedPreferences.Editor接口对象中,也可以使用remove (String key)方法以删除存在的参数 key 所标记的数据内容。或者直接使用clear()方法清空设置的所有数据内容。

在通过SharedPreferences.Editor接口对象设置或删除完数据后,调用其apply()commit()方法以一次性提交设置的所有数据,在提交之后系统会将上文设置的数据都保存到SharedPreferences文件中。

虽然commit()方法可以返回boolean值以判断是否提交成功,但并不推荐使用该方法;使用apply()方法可以更安全的保证提交的数据成功保存。

文件读取数据

如果想读取SharedPreferences对象所在文件的数据,就没有将数据写入文件那么繁琐的步骤了。只需要直接调用SharedPreferences对象的getBoolean(String key, boolean defValue)获取boolean类型的数据值,getFloat(String key, float defValue)获取float类型的数据值,getStringSet(String key, Set<String> defValues)获取Set<String>类型的数据值等。这一系列的获取方法,其参数一 key 与写入文件时的设置方法中的参数 key 一致,以标记响应数据;参数二 defaultValue 则是默认的数据值,当SharedPreferences文件中并没有保存参数 key 对应的数据时,将会返回 defaultValue 所设置的数值。

如果保存的数据量并不多,也可以直接调用SharedPreferences对象的getAll()方法,获取Map<String, ?>集合类型的所有数据,再对得到的数据分别操作处理。

另外SharedPreferences对象的contains(String key)方法,也可以只判断当前SharedPreferences对象所在文件中是否有参数 key 所标记的数据内容,返回boolean类型的结果。

文件修改的实时监听

可以用SharedPreferences对象的registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)方法,实时监听当前SharedPreferences文件的修改操作。

参数 listenerandroid.content.SharedPreferences.OnSharedPreferenceChangeListener接口的实例化对象,在该接口中实现了onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)方法。

一旦 listener 被注册,在参数 sharedPreferences 对应的文件中数据标记的 key 在被修改后, listener 中的onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)方法将会被系统回调。

对于已经注册的 listener ,尤其记得要在不需要监听之后,调用SharedPreferences对象的unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener),将之前注册的OnSharedPreferenceChangeListener对象撤销掉,以防止在后续出现内存泄漏的问题。


轻量级的SharedPreferences存储方式,可以很方便的存储一些简单数据,其内存效率是比较高的。然而如果应用程序中所有的数据都使用这种存储方式,反而使SharedPreferences文件的操作效率降低了,而且所有数据都使用这种键值对的形式存取,也会增加代码量。那么有什么更合适的存储方式适合不同类型的数据吗?详情请关注下一篇文章。

Android系统编程入门系列之应用内键值对数据的简单保存的更多相关文章

  1. Android系统编程入门系列之应用内数据保存数据库

    上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分 ...

  2. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  3. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  4. Android系统编程入门系列之硬件交互——多媒体摄像头

    多媒体系列硬件 多媒体包括图片.动画.音频.视频,这些多媒体素材的采集(输入)主要依靠摄像头和麦克风等硬件设备转化为基础数据,而他们的播放渲染(输出),则需要依靠具有相关功能的编解码软件.当然随着硬件 ...

  5. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

  6. Android系统编程入门系列之界面Activity交互响应

    在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应.本文 ...

  7. Android系统编程入门系列之界面Activity响应丝滑的传统动画

    上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化.然而不管是启动一个界面执行新界 ...

  8. Android系统编程入门系列之界面Activity响应多元的属性动画

    在响应丝滑动画一篇文章中,分别介绍了作用于普通视图.绘制视图的绘制对象.和界面这三种对象的动画效果,但是都有一些使用的局限性.比如这些动画都只是以屏幕上绘制更新的方式绘制动画,并没有真实改变作用对象的 ...

  9. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

随机推荐

  1. mysql为什么用b+树做索引

    关键字就是key的意思 一.B-Tree的性质 1.定义任意非叶子结点最多只有M个儿子,且M>2: 2.根结点的儿子数为[2, M]: 3.除根结点以外的非叶子结点的儿子数为[M/2, M]: ...

  2. 基于ifix组态软件研究控制按钮权限

    背景: 在前阵子做基于ifix生成电力监控平台时,遇到业主提出的一个需求.关于如何在控制弹窗中,点击相应的合分闸按钮时,优先弹出登录界面,当输入相应的有权限用户名和密码后,才能操作这一要求.后实现如下 ...

  3. Thinkphp中取消url中的index.php 和 Home 默认模块

    将配置文件中改: <?phpreturn array(    //'配置项'=>'配置值'    'URL_MODEL'=>'2',   //去掉url中index.php    ' ...

  4. <题解>[IOI2019]景点划分

    题目传送门(luogu) 题目传送门(loj) 这个题对我来说可以算是超出了我的能力范围 被学长拿来教我做构造,构造题真简单,构造题真是人,构造题真能手切... 首先对于本题,必须要知道dfs树这东西 ...

  5. 还在用Postman?来,花2分钟体验下ApiPost的魅力

    2分钟玩转APIPOST 本文通过简单介绍如何利用ApiPost调试接口和快速的生成接口文档,让您初步体验ApiPost的魅力! 1. API写完想要测试?试试模拟发送一次请求 新建接口,我想模拟发送 ...

  6. HCNA Routing&Switching之VLAN间路由

    前文我们了解了二层交换技术vlan相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15091491.html:今天我们来聊一聊不同VLAN间通信相关话题 ...

  7. python实现常用五种排序算法

    一.冒泡排序 原理: 比较相邻的元素.如果第一个比第二个大就交换他们两个 每一对相邻元素做同样的工作,直到结尾最后一对 每个元素都重复以上步骤,除了最后一个 第一步: 将乱序中的最大值找出,逐一移到序 ...

  8. (11)MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)

    1.概述 前面章节之所以介绍那么多锁的知识点和示例,其实最终目的就是为了排查与解决死锁的问题,下面我们把之前学过锁知识重温与补充一遍,然后再通过例子演示下如果排查与解决死锁. 2.前期准备 ●数据库事 ...

  9. 获取浏览器中url的参数

    例如: 浏览器的地址是:http://localhost:8080/src/views/moneyDetail?id=10 vue 获取浏览器的参数 获取id的参数:this.$route.query ...

  10. Android Jetpack 架构组件最佳实践之“网抑云”APP

    背景 近几年,Android 相关的新技术层出不穷.往往这个技术还没学完,下一个新技术又出来了.很多人都是一脸黑人问号? 不少开发者甚至开始哀嚎:"求求你们别再创造新技术了,我们学不动了!& ...