首页 > 代码库 > SharedPreferences详解

SharedPreferences详解

很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下:
SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();//获取编辑器
editor.putString("name", "传智播客");
editor.putInt("age", 4);
editor.commit();//提交修改
生成的itcast.xml文件内容如下:
<?xml version=‘1.0‘ encoding=‘utf-8‘ standalone=‘yes‘ ?>
<map>
<string name="name">传智播客</string>
<int name="age" value="http://www.mamicode.com/4" />
</map>
因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。
另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。
-----------------------------------------------------------------------

访问SharedPreferences中的数据代码如下:
SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);
//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 1);

如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>为cn.itcast.action的应用使用下面语句创建了preference。
getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);
其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :
Context otherAppsContext = createPackageContext("cn.itcast.action", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 0);

如果不通过创建Context访问其他应用的preference,可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如:
File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);//<package name>应替换成应用的包名

 

 

—————————————又一个———————————————————————————————

——————————————————————————————————————————

我们在开发软件的时候,常需要向用户提供软件参数设置功能,例如我们常用的微信,用户可以设置是否允许陌生人添加自己为好友.对于软件配置参数的保存,如果是在window下通常我们会采用ini文件进行保存.如果是J2EE下面,我们会采用properties属性文件或者xml进行保存.在我们的Android应用中又适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级应用程序内部轻量级的存储方案,特别适合用于保存软件配置参数,比如boolean,int,float,long,String等数据.使用SharedPreferences保存数据,其实质是采用了xml文件存放数据,路径为:/data/data/<package name>/shared_prefs.

获取SharedPreferences的两种方式:
1 调用Context对象的getSharedPreferences()方法
2 调用Activity对象的getPreferences()方法
两种方式的区别:
调用Context对象的getSharedPreferences()方法获得的SharedPreferences对象可以被同一应用程序下的其他组件共享.
调用Activity对象的getPreferences()方法获得的SharedPreferences对象只能在该Activity中使用.
 
SharedPreferences的四种操作模式:
Context.MODE_PRIVATE
Context.MODE_APPEND
Context.MODE_WORLD_READABLE
Context.MODE_WORLD_WRITEABLE
 
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件.
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件.
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取.
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入.
将数据保存至SharedPreferences:
SharedPreferences preferences=getSharedPreferences("user",Context.MODE_PRIVATE);
Editor editor=preferences.edit();
String name="xixi";
String age="22";
editor.putString("name", name);
editor.putString("age", age);
editor.commit();
 
从SharedPreferences获取数据:
SharedPreferences preferences=getSharedPreferences("user", Context.MODE_PRIVATE);
String name=preferences.getString("name", "defaultname");
String age=preferences.getString("age", "0");

 

 

 

———————————————又有一个—————————————————————————————

——————————————————————————————————————————————————

这是我最近碰到过的一个问题,之前并没有一个清晰的认识!唯一的印象是,SharedPreferences 是可以用来存取数据。直到前些日子,在360漏洞扫描应用后,才意识到这个问题,如何正确的使用SharedPreferences呢?以下是360漏洞扫描的信息:

技术分享

 

关于SharedPreferences顺便再复习一下:

 

SharedPreferences 是Android 中的内置API,它允许我们存取键值对形式的基础类型数据,像:boolean,float ,int , long , string 。这些数据将会持久化的存在,即使你的应用程序结束之后(注意:如果应用从手机上写在掉后,该程序对应的SharedPreferences将会消失,保存在路径:/data/data/<package_name>/shared_prefs 目录下)

 

注意:User Preferences 用户配置

 

严格来说,SharedPreferences最好不要用来保存“用户配置”,比如,用户选择了什么铃声,是否自动更新等等。如果要为应用创建用户配置,可以使用PreferenceActivity,它可以用来创建“用户配置”。(PreferenceActivity用来创建程序中的设置界面)

 

 

如何在应用程序中获取SharedPreferences呢?有两个方法:

 

getSharedPreferences(name , mode) - 如果你的应用需要多个preferences文件可以使用该方法。该方法的第一个参数,用来区别不同的preferences文件。

比如:

 

SharedPreferences sp1 = getSharedPreferences("sp_1" , Context.MODE_PRIVATE);

SharedPreferences sp2 = getSharedPreferences("sp_2" , Context.MODE_PRIVATE);

是同一个应用程序的两个不同的配置文件。

 

该方法的第二个参数支持如下几种值:

Context.MODE_PRIVATE:指定该SharedPreferences数据只能被本应用程序或者是拥有相同user ID的应用读、写。

 

Context.MODE_WORLD_READABLE :指定该SharedPreferences数据能被其它应用程序读,但不能写。

这个变量在API 17以后已经不建议使用了。创建全局可读文件是非常危险的事,这样会引起程序的安全漏洞。程序之间的交互应该更多的使用正规的途径,比如:ContentProvider, BroadcastReceiver, and Service.当程序通过备份和恢复后,并不能保证这种获取方式依然对该文件有效。文件创建模式:允许所有的其它程序来读取创建的文件。

Context.MODE_WORLD_WRITEABLE:指定该SharedPreferences数据能被其它应用程序读,写。

 

这个变量在API 17以后已经不建议使用了。创建全局可写文件是非常危险的事,这样会引起程序的安全漏洞.程序之间的交互应该更多的使用正规的途径,比如:ContentProvider, BroadcastReceiver, and Service.当程序通过备份和恢复后,并不能保证这种获取方式依然对文件有效。文件创建模式:允许所有的其它程序来修改创建的文件。

 

Context.MODE_MULTI_PROCESS

在API11中添加,SharedPreferences加载标记:被设置后,在硬盘上的文件在被修改是将会被检查如果当前的SharedPreferences实例已经被加载进进程后。这种情况通常发生在,当程序有多个进程在修改同一个SharedPreferences文件的时候。通常来说这种方式在进程之间交互表现是非常好的。

 

 

 

在API 2.3之前,发布release版本时,这个标记是默认存在的,当发布release版本时。对于使用2.3以上的sdk进行编译的时候,如果想使用那么

必须明确的设置。

 

getPreferences() - 如果你的Activity仅仅需要一个preferences文件可以使用这个方法。因为你的Activity只要一个preferences文件,所以不需要提供名字。

 

如何往SharedPreferences中写数据呢?

 

1、需要获取SharedPreferences的编辑对象即:SharedPreferences.Editor :  使用 edit()。

比如:SharedPreferences.Editor  editor = sp1.edit();

2、使用putXXX()方法,向preferences写入数据:

比如:editor.putXXX(“key” , value);

3、向preferences文件中提交数据:

比如:editor.commit();

 

如何读取数据呢?

使用方法getXXX()等方法读取。

比如:

boolean silent = settings.getBoolean("silentMode", false);

 

 

下面是Google doc提供的一个demo:

[java] view plain copy print?
  1. public class Calc extends Activity {  
  2.     public static final String PREFS_NAME = "MyPrefsFile";  
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle state){  
  6.        super.onCreate(state);  
  7.        . . .  
  8.   
  9.        // Restore preferences  
  10.        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);  
  11.        boolean silent = settings.getBoolean("silentMode", false);  
  12.        setSilent(silent);  
  13.     }  
  14.   
  15.     @Override  
  16.     protected void onStop(){  
  17.        super.onStop();  
  18.   
  19.       // We need an Editor object to make preference changes.  
  20.       // All objects are from android.context.Context  
  21.       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);  
  22.       SharedPreferences.Editor editor = settings.edit();  
  23.       editor.putBoolean("silentMode", mSilentMode);  
  24.   
  25.       // Commit the edits!  
  26.       editor.commit();  
  27.     }  
  28. }  
技术分享
public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";

    @Override
    protected void onCreate(Bundle state){
       super.onCreate(state);
       . . .

       // Restore preferences
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }

    @Override
    protected void onStop(){
       super.onStop();

      // We need an Editor object to make preference changes.
      // All objects are from android.context.Context
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);

      // Commit the edits!
      editor.commit();
    }
}

 

接下来看Google doc 中关于sharedpreferences的文档。

 

SharedPreferences 本身是一个接口,用来获取和修改程序的配置数据,位于:android.content.SharedPreferences。程序无法直接创建SharedPreferences实例,只能通过conext的getSharedPreferences(String, int)的获取接口实例。

 

注意:当前类不支持跨进程调用,将会在之后的版本中支持。

 

它提供了如下方法来访问perferences数据:

 

boolean contains(String key) :判断当前preferences是否包含key所对应的数据。

 

abstract SharedPreferences.Editor edit():为preferences创建一个新的Editor,因此你可以修改preferences的数据并且提交给SharedPreferences对象。

 

 

abstract Map<String, ?> getAll() :获取preferences中所包含的所有数据。

 

 

abstract XXX getXXX(String key, boolean defValue):获取perferences里指定的key对应的value。如果该key不存在,则返回默认defValue .其中XXX是基础数据类型:boolean、float、int、long、String等。

 

SharedPreferences接口本身并没有提供写入数据的能力,而是通过SharedPreferences的内部接口,SharedPreferences调用edit()方法即可获取它所对应的Editor对象。

 

Editor提供了如下方法来写向perferences入数据:

 

 

abstract SharedPreferences.Editor clear()

在Editor中标记出:清除所有preferences保存的数据。(注意此方法并没有实质性的清除,只是在Editor上进行了标记,需要commit后才可以进行真正的清除)

 

abstract boolean commit():

将Editor对preferences的修改提交给SharedPreferences对象,完成对preferences中数据的修改。

 

abstract SharedPreferences.Editor putXXX(String key, boolean value)

向preferences中存入key及其所对应的数据 <key-value>。其中xxx可以是boolean、float、int、long、String等各种基本类型的数值。

 

abstract SharedPreferences.Editor remove(String key):

在Editor中标记出preference中以key以键的键值对应该被移除,而实际的移除动作将会在commit()执行之后才会作用于真正的preferences。

 

如何读取其它应用的SharedPreferences:

 

 如上所述,如果想读、写其它应用的SharedPreferences,前提是创建该SharedPreferences的应用程序指定相应的访问权限,例如指定了MODE_WORLD_READABLE , 这表明该SharedPreferences可被其它应用程序读取。指定了MODE_WORLD_WRITEABLE,这表明该SharedPreferences可被其它程序写入。

 

为了读取其它程序对应的Context,可按照如下步骤进行:

1、需要创建其它程序对应的Context,例如如下代码:

Context userCount  = createPackageContext(“com.sharedpreferencesdemo.zhanggeng” , Context.CONTEXT_IGNORE_SECURITY);

 

上面的程序中:com.sharedpreferencesdemo.zhanggeng 就是其他程序的包名——实际上Android系统就是用应用程序的报名来作为程序的标识的。

2、调用其它程序的conext的getSharedPreferences(String name , int mode) 即可获取相应的SharedPreferences对象。

3、调用SharedPreferences的edit()方法获取相应的Editor即可。

 

如下demo所示:

[java] view plain copy print?
  1. private void readOtherAppSp() {  
  2.         Context useCount = null;  
  3.   
  4.         try {  
  5.             //获取其它程序对应的Context  
  6.             useCount = createPackageContext("com.sharedpreferencesdemo.zhanggeng" , Context.CONTEXT_IGNORE_SECURITY);  
  7.         } catch (PackageManager.NameNotFoundException e) {  
  8.             e.printStackTrace();  
  9.         }  
  10.         //使用其它程序的Context获取对应的SharedPreferences  
  11.         SharedPreferences prefs = useCount.getSharedPreferences("count" , Context.MODE_WORLD_READABLE);  
  12.         //读取数据  
  13.         int count = prefs.getInt("count" , 0);  
  14.         //后续处理.....  
  15.     }  
技术分享
private void readOtherAppSp() {
        Context useCount = null;

        try {
            //获取其它程序对应的Context
            useCount = createPackageContext("com.sharedpreferencesdemo.zhanggeng" , Context.CONTEXT_IGNORE_SECURITY);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        //使用其它程序的Context获取对应的SharedPreferences
        SharedPreferences prefs = useCount.getSharedPreferences("count" , Context.MODE_WORLD_READABLE);
        //读取数据
        int count = prefs.getInt("count" , 0);
        //后续处理.....
    }

 

那么回到最初的问题,改如何正确的使用SharedPreferences?

1、设置相应的权限:如果只供本程序或者有相同user id的程序使用 使用Context.MODE_PRIVATE权限;如果允许其它程序可读设置权限;如果允许其它程序可写设置相应权限;

2、SharedPreferences保存的数据最好是基础数据类型(当然也可以用来保存用户配置,官方推荐PreferenceActivtiy )。

3、如果想让程序有多个preferences文件使用getSharedPreferences(xxx , xxx);如果想让程序只有一个preferences使用getPreferences()。

4、SharedPreferences最好不要用来保存多个程序交互使用的共享数据,建议使用ContentProvider, BroadcastReceiver, and Service 来完成多个程序之间的数据共享。

 

参考文档:

1、http://developer.android.com/reference/android/content/SharedPreferences.html

 

SharedPreferences详解