了解Android API中的SharedPreferences

Preference翻译为偏好,但实际上它可以算是Setting(设置)的别名。两种叫法给人的差异在于针对的对象不同:设置更倾向于设备的属性,修改设置便是改变设备的功能;偏好则倾向于用户的性格,用户基于其个人的偏好来来形成设备的差异化。但是总体而言,它们是一致的,都是通过用户的需求改变设备的体验。

在Android的开发过程中,会在使用的API中见到很多名字中带有Preference的类和接口,此篇文章就来介绍一下这些“*Prefere*”的功能和用途。

在Android提供API中,带有Preference的其实主要分为两类:一类是android.content包下的SharedPreferences,另一类则是android.preference包下的Preference。它们分别实现不同功能,却又相互联系合作完成对Android程序的控制。

SharedPreferences简介

SharedPreferences是以复数形式存在,因为在Android中它是用来存储键值对(Key-Value Pair)数据的集合。API中包含了多个方法来方面读取相应类型的数据:


  1. String getString(String key, String defValue); 
  2. Set<String> getStringSet(String key, Set<String> defValues); 
  3. int getInt(String key, int defValue); 
  4. long getLong(String key, long defValue); 
  5. float getFloat(String key, float defValue); 
  6. boolean getBoolean(String key, boolean defValue);  

这也表明SharedPreferences所能存储的类型被限定在了String、int、long、float、boolean这些基础数据类中,唯一的集合类型也只是Set,而它看起来更像是用来作为不能有重复数据的数组。

还可以单纯检查是否包换指定的主键,或者干脆将所有的键值对的Map获取出来:


  1. boolean contains(String key);     
  2. Map<String, ?> getAll();  

Android系统的工程师在设计SharedPreferences的时候,把读取的功能放在了SharedPreferences上,而把写回的功能实现在了其内嵌的Editor类上,通过调用edit()方法来获得一个写入器。这样就很容易实现一个只读的对象,只要返回一个空指针或非可用的Editor对象就可以了。


  1. Editor putString(String key, String value); 
  2. Editor putStringSet(String key, Set<String> values); 
  3. Editor putInt(String key, int value); 
  4. Editor putLong(String key, long value); 
  5. Editor putFloat(String key, float value); 
  6. Editor putBoolean(String key, boolean value); 
  7. Editor remove(String key);  

SharedPreferences还有一个内嵌接口OnSharedPreferenceChangeListener,实现它唯一的方法onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)并通过以下方法添加在SharedPreferences对象上就可以监听其上键值对的增加、删除和修改:


  1. void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener); 
  2. void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);  

SharedPreferences的在Android系统中的实现

SharedPreferences和内嵌的Editor其实都只是接口定义而已,并没有实现任何方法。它只是用来制定了一个存储键值对的协议,具体的实现方式和存储形式可以是任意的。在Android系统中,它默认以XML格式的文件来存储这些数据,实现的类则是SharedPreferencesImpl。

下边就是所保存的XML文件的基本格式,它以数据类型作为XML元素的标签,主键(key)是标签name属性的值,而主键对应的值则作为value属性的值。但如果是String类型则作为标签下的content,这样就不用转义引号也能更好的处理换行。另外对于null值存储的结构也比较特殊,它以null为标签,只有一个name属性,没有其他内容。


  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?> 
  2. <map> 
  3.     <string name="Name">Ider</string> 
  4.     <boolean name="Android" value="true" /> 
  5.     <set name="Subsites"> 
  6.         <string>code.iderzheng.com</string> 
  7.         <string>blog.iderzheng.com</string> 
  8.         <string>manual.iderzheng.com</string> 
  9.     </set> 
  10.     <int name="VersionCode" value="21" /> 
  11.     <long name="VersionNumber" value="1355" /> 
  12.     <float name="Version" value="5.0" /> 
  13.     <null name="Null" /> 
  14. </map>  

Android系统会把该XML文件存储在/data/data/(packagename)/shared_prefs/下,每一个XML文件就对应一个SharedPreferences对象(实际是SharedPreferencesImpl对象)。但是SharedPreferences是接口不能用来实例化对象,而SharedPreferencesImpl是系统隐藏类,不能被直接访问使用,其构造函数也只是包可见。所以不能通过new来构建一个SharedPreferences,必须通过Context提供的getSharedPreferences(String, int)来获得实例。

该方法的第一个参数是指定XML文件名(不包含“.xml”后缀)的字符串,方法会去读取出对应的文件,创建一个SharedPreferences对象。第二个参数指定文件的访问权限,共有4中可选模式,从API 17开始基于安全的考虑,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE已经被废弃使用,只有MODE_PRIVATE和MODE_MULTI_PROCESS可使用,一般情况下指定MODE_PRIVATE即可。

对于从SharedPreferences中读取指定主键的值是十分快的,因为所有存在XML的键值对信息全都被读取被存储在了SharedPreferences对象中的Map成员变量里,所以读取都是基于内存访问。使用Editor写回到文件是避不开IO操作的,所以使用commit()提交修改还是会花费一些时间。考虑到这点,Android在API 9里引进了apply()方法来异步地将修改后的内容写回到文件,当然在写回前也会先更新内存中的键值对信息保证读取到的时最新的内容。

既然写回可以是异步的,那么多次调用getSharedPreferences(String, int)获得多个SharedPreferences赋值给不同的变量,假如一个变量做了修改,其他的对象不是会出现内容不一致的情况。其实这种情况并不会出现,因为所有创建出来的SharedPreferences都被存储在ContextImp的一个静态成员变量中:


  1. /** 
  2. * Map from package name, to preference name, to cached preferences. 
  3. */ 
  4. private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;  

这是一个从程序的Package名字到XML文件名再到SharedPreferences对象的二级Map。所以每次调用getSharedPreferences(String, int)得到的对象其实都是同一个实例,修改操作也都就作用在同一段内存中保证了所有访问的一致性。apply()方法也会自动将所有修改排入队列一一写回文件从而不会因为顺序的错误而造成意料之外的错误覆盖。所以因为这个缓存机制的存在,多次调用getSharedPreferences(String, int)是非常效率的。而写回时则推荐使用apply()实现异步操作,而不要用commit()阻碍主线程。

SharedPreferences的使用和示例

一般而言SharedPreferences的名字和主键名都是固定的,所以可以定义一些final的字符串变量来保存这些名字,在读取和写回时都使用这些常熟变量。对于之前展示的XML对应的代码就如下边所示:


  1. private static final String IDER_PREFERENCE = "ider-preference"; 
  2. private static final String IDER_PREFERENCE_KEY_NAME = "Name"; 
  3. private static final String IDER_PREFERENCE_KEY_SUBSITES = "Subsites"; 
  4. private static final String IDER_PREFERENCE_KEY_IS_ANDROID = "Android"; 
  5. private static final String IDER_PREFERENCE_KEY_VERSION = "Version"; 
  6. private static final String IDER_PREFERENCE_KEY_VERSION_CODE = "VersionCode"; 
  7. private static final String IDER_PREFERENCE_KEY_VERSION_NUMBER = "VersionNumber"; 
  8. private static final String IDER_PREFERENCE_KEY_NULL = "Null"; 
  9. public void write(Context context) { 
  10.     final SharedPreferences spref = context.getSharedPreferences(IDER_PREFERENCE, MODE_PRIVATE); 
  11.     HashSet<String> strs = new HashSet<String>(); 
  12.     strs.add("blog.iderzheng.com"); 
  13.     strs.add("code.iderzheng.com"); 
  14.     strs.add("manual.iderzheng.com"); 
  15.     SharedPreferences.Editor editor = spref.edit(); 
  16.     editor.putString(IDER_PREFERENCE_KEY_NAME, "Ider"); 
  17.     editor.putStringSet(IDER_PREFERENCE_KEY_SUBSITES, strs); 
  18.     editor.putBoolean(IDER_PREFERENCE_KEY_IS_ANDROID, true); 
  19.     editor.putFloat(IDER_PREFERENCE_KEY_VERSION, 5.0f); 
  20.     editor.putInt(IDER_PREFERENCE_KEY_VERSION_CODE, 21); 
  21.     editor.putLong(IDER_PREFERENCE_KEY_VERSION_NUMBER, 1355); 
  22.     editor.putString(IDER_PREFERENCE_KEY_NULL, null); 
  23.     editor.apply(); 
  24. public void read(Context context) { 
  25.     final SharedPreferences spref = context.getSharedPreferences(IDER_PREFERENCE, MODE_PRIVATE); 
  26.     String name = spref.getString(IDER_PREFERENCE_KEY_NAME, ""); 
  27.     Set<String> strs = spref.getStringSet(IDER_PREFERENCE_KEY_SUBSITES, null); 
  28.     boolean isAndroid = spref.getBoolean(IDER_PREFERENCE_KEY_IS_ANDROID, false); 
  29.     float version = spref.getFloat(IDER_PREFERENCE_KEY_VERSION, 0); 
  30.     int versionCode = spref.getInt(IDER_PREFERENCE_KEY_VERSION_CODE, 0); 
  31.     long versionNumber = spref.getLong(IDER_PREFERENCE_KEY_VERSION_NUMBER, 0); 
  32.     boolean hasKey = spref.contains(IDER_PREFERENCE_KEY_NULL); 
  33. }  

既然SharedPreferences的名字是可以任意给定的,所以对于SharedPreferences的使用就可以有非常的针对性创建不同的文件来存储不同的内容。比如可以以不同用户为名存放他们的偏好信息,可以根据不同界面保存布局信息、已访问的页码。Activity就额外实现了获取SharedPreferences的方法getPreferences(int),它只需要开发者提供文件的打开模式,自动以Activity的类名作为文件名。

SharedPreferences取值时是直接将给定主键在Map中的值强制转换成所需要的值,所以如果用putInt存储了整型却用getBoolean()来取,并不会自动转换成布尔型,而是直接抛出异常,所以要使用要注意保持类型一致。

另外如果没有存储过某个主键,SharedPreferences会返回null值,而对于String、Set这些类型同样可以存储null值,这样就不能确定null是不是真是存储的数据了。因此SharedPreferences还提供了contains (String key)方法来检查给定的主键是真的存了null,还是因为并没有这个键值对才返回的null。

SharedPreferences的优缺点

之前讲过所以读取过的SharedPreferences的文件都会被缓存在Map里放在内存中,以便下次直接快速访问,因为快事SharedPreferences的一大优点。但是也因为都背缓存,而且存放格式是XML,所以SharedPreferences不宜存放过多的键值对,值的内容也不能太大。再者SharedPreferences只支持最基本的几种类型,存储一些用户基本信息也足够了。

如果对设备有root权限,那么就可以直接访问/data/data/(packagename)/shared_prefs/目录,将XML文件转出来查看。或者直接用在adb shell下直接用cat指令观察数据的改变,非常的方便。

综合而言,存储一些内容较小、类型简单的数据,SharedPreferences绝对是首选对象。

本文作者:佚名

来源:51CTO

时间: 2024-10-16 05:11:21

了解Android API中的SharedPreferences的相关文章

我要获取anroid系统,&amp;amp;quot;是否开启了默认锁屏&amp;amp;quot;,在android api中未查找到参数,如下图.

问题描述 我要获取anroid系统,"是否开启了默认锁屏",在android api中未查找到参数,如下图. 我开始想通过"Settings.System.getInt"来获取参数,但读了anroid api下Settings.System的参数,没找着合适的,各位大神,有没有好办法 解决方案 http://www.2cto.com/kf/201404/296615.html

Android应用中使用SharedPreferences类存储数据的方法_Android

在Android系统中提供了多种存储技术.通过这些存储技术可以将数据存储在各种存储介质上.比如sharedpreferences可以将数据保存着应用软件的私有存储区,这些存储区的数据只能被写入这些数据的软件读取.当然Android还支持文件存储.SQLite数据库和Content Provider.在这里我们将对sharedpreferences存储方式进行介绍. SharedPreferences是一种轻量级的数据存储方式,学过Web开发的同学,可以想象它是一个小小的Cookie.它可以用键值

Android应用中使用SharedPreferences类存储数据的方法

在Android系统中提供了多种存储技术.通过这些存储技术可以将数据存储在各种存储介质上.比如sharedpreferences可以将数据保存着应用软件的私有存储区,这些存储区的数据只能被写入这些数据的软件读取.当然Android还支持文件存储.SQLite数据库和Content Provider.在这里我们将对sharedpreferences存储方式进行介绍. SharedPreferences是一种轻量级的数据存储方式,学过Web开发的同学,可以想象它是一个小小的Cookie.它可以用键值

Android开发中WebView与原生JS的数据交互详解

关于WebView 我们知道目前android市场上的一些应用采用的开发方式大致分为三种:Native App.Web App.Hybrid App.本文主要是Hybrid App中实现的主要技术native组件与js的数据交互的理解以及实现. Android API中提供了WebView组件来实现对html的渲染.所谓的HybridApp开发方式即是汇集了HTML5.CSS3.jS的相关开发技术,以及数据交换格式json/XML.这显然是Web开发工程师的技能.正是因为如此,众多中小企业选择了

在Android应用中使用百度地图api

本篇通过一个简单的示例一步步介绍如何在Android应用中使用百度地图api. 1)下载百度地图移动版 API(Android)开发包 要在Android应用中使用百度地图API,就需要在工程中引用百度地图API开发包,这个 开发包包含两个文件:baidumapapi.jar和libBMapApiEngine.so.下载地址: http://dev.baidu.com/wiki/static/imap/files/BaiduMapApi_Lib_Android_1.0.zip 2)申请API K

在Android系统中使用Adobe AIR地理定位API

在你的Android设备中,当设备位置发生变化时,利用下列任意一个位置源,你的应用程序能够收到变化的更新信息,其中包括高度.精确度.方向.速度和时间戳等信息: GPS卫星: 当使用GPS传感器时,支持精确定位功能. 无线网络:当使用数据连接时,支持近似定位功能. Geolocation API可以为创建应用程序提供必要的支持功能,它能够使用在设备中配置的位置源信号. 在本文中,你将了解: Geolocation API 在应用程序中处理Geolocation事件 Android相关的设备许可 应

简介Android应用中sharedPreferences类存储数据的用法_Android

在Android开发中,经常会遇到这样一种情况,即需要将用户偏好设置(如用户偏好的app色彩主题).与特定登录用户相关的设置(如不同登陆用户的偏好).整个app的生命周期内的设置(如首次登陆显示介绍页)存储在用户本地,那么首先考虑使用sharedPreferences.这是Android中专门用来存储轻量级键值对数据的类,会在本地以xml文件形式存储. 一. 运行机制接口:SharedPreferencesImpl在该接口中,定义了一个Editor接口.一个edit方法.多个get方法.一个监听

android百度地图api 的一些类我用不了。可是官方api中明明有给出。

问题描述 android百度地图api 的一些类我用不了.可是官方api中明明有给出. 还有关于overlaymanager的类 我都用不了.可是官网api明明给出了这个类的啊.我下载了最全的sdk. 希望有人帮我下 感激不尽.文档"> //官方api的部分截图 解决方案 Android 百度地图API 定位 导航Android 百度地图API 定位 导航 代码 解决方案二: 有这个jar包吗..... 解决方案三: 所用百度地图API为3.6版,而BMapManager在3之后就弃用了,

android-最新版Android百度地图Api中zoomToSpan没有用?求大神解决。。。

问题描述 最新版Android百度地图Api中zoomToSpan没有用?求大神解决... 代码如下: /** * 在百度地图上显示搜索的结果; */ private void showSearchResultInBaiduMap() { MyOverlayManager overlay = new MyOverlayManager(mBaiduMap); mBaiduMap.setOnMarkerClickListener(overlay); overlay.addToMap(); overl