Android系统编程入门系列之应用内键值对数据的简单保存
在应用程序间及与用户的通信交互过程中,会产生并传递一系列数据。针对这些数据,有部分是只在应用程序中使用的缓存数据,还有一部分是在不同位置多次或长时间使用的持久化数据。
对于缓存数据来说,通常以代码中定义局部变量或全局变量的方式访问使用,这种使用方式伴随在编程的整个过程中;而持久化数据,则需要以特定的文件格式保存在系统硬盘中,使用系统提供的框架方法来访问使用。而根据要持久化保存数据的复杂程度不同,分别有轻量级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
对象时,系统检测当前应用程序内部存储空间中是否有指定 name 的 xml 格式文件,若没有将会先创建。之后系统便会打开该文件,通过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
文件的修改操作。
参数 listener 是android.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
文件的操作效率降低了,而且所有数据都使用这种键值对的形式存取,也会增加代码量。那么有什么更合适的存储方式适合不同类型的数据吗?详情请关注下一篇文章。