SharedPreferences 详解(多进程,存取数组解决方案)

一、SharedPreferences基本概念

文件保存路径:/data/data/<包名>/shared_prefs目录下目录下生成了一个SP.xml文件

SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。

实现SharedPreferences存储的步骤如下:

  1. 根据Context获取SharedPreferences对象
  2. 利用edit()方法获取Editor对象。
  3. 通过Editor对象存储key-value键值对数据。
  4. 通过apply()或者commit()方法提交数据。

二、SharedPreferences相关api

  • SharedPreferences.Editor api:完成数据写入操作
  • SharedPreferences api :完成数据读取操作

说明:所以的getXXX()方法,都支持默认值,即如果没有找到与当前key值对应的value,则返回我们自己设置的默认值。

  • commit()方法与apply()方法的比较

相同点:

  1. 二者都是提交preference修改数据
  2. 二者都是原子过程。

区别:

  1. apply没有返回值而commit返回boolean表明修改是否提交成功
  2. apply是将修改数据原子提交到内存,而后异步真正提交到硬件磁盘;而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。
  3. apply方法不会提示任何失败的提示。

综合上述,由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。

  • 对api的理解

1. commit介绍:public abstract boolean commit ()

       修改你的preferences,从Editor到SharePreferences。它执行所请求的修改,替代SharedPreferences中的任何数据,当2个editor同时修改preferences ,最后一个commit成功。如果不关注返回值或在程序的main线程使用时,推荐使用apply(). 2. apply介绍:public abstract void apply ()         区别:commit将同步的将数据写到preferences;apply立即更改内存中的SharedPreferences,但是开始异步提交到磁盘中。保存失败你也不会得到任何提示信息,如果在这个sharedPreferences有另外一个editor执行一个定期的commit,此时一个apply依旧未完成。commit将被阻塞,直到所有异步操作完成,以及自己的commit。由于SharedPreferences在进程中是单实例的。在忽悠返回值的前提下,取代任何实例的commit或apply都是安全的。

来源: <http://tanqi0508.blog.163.com/blog/static/1883557772012111104326404/>

三、对数据集合的支持——可以直接写入一个 Set<String>类型的集合,但是默认只支持HashSet<String>类型,其他类型会被自动转型

Set<String>是一个接口,一般使用子类来完成相关的功能。

       如果你希望传入的Set是一个有序的(跟插入时的顺序一样),那么使用LinkedHashSet<String>类型,构造好一个LinkedHashSet<String>对象之后,调用 SharedPreferences.EditorputStringSet(String key, Set<String> values)写入。  按照常规的思维,通过SharedPreferences的getStringSet(String key)方法读取出来数据,然后强制转为LinkedHashLinked<String>,可是出现异常了,系统提示不能将HashSet<String>转为LinkedHashSet<String>类型。也就是说取出来的值已经不再是我们写入的类型了。所以就只能使用HashSet<String>默认的排序类型,这只能满足那些不关系顺序的情况。

四、SharedPreferences一次存入多个有序数据解决方案 (String 类型为例)——使用字符串拼接(StringBuilder)的方式

public void testSharedPreferences(Context context) {
        // 写数据操作
        final String regularExpression = "#";
        final String key = "key";
        final String[] strings = { "1111", "2222", "3333" };
        final String defaultValue = "5555";
        final String fileName = "filename";
        final StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < strings.length; i++) {
            stringBuilder.append(strings[i]);
            if (i != strings.length - 1) {
                stringBuilder.append(regularExpression);
            }
        }
        SharedPreferences preferencesWrite = context.getSharedPreferences(fileName, Context.MODE_WORLD_READABLE);
        SharedPreferences.Editor editor = preferencesWrite.edit();
        editor.putString(key, stringBuilder.toString());
        editor.apply();
  
       // 读数据操作
        SharedPreferences preferencesRead = context.getSharedPreferences(fileName, Context.MODE_WORLD_READABLE);
        final String resultStr = preferencesRead.getString(key, defaultValue); // 没有对应的key则返回“5555”
        final String[] resultArray = resultStr.split(regularExpression);  // 解析数据,字符串分割
        for (String str : resultArray) {
            System.out.println(str);
        }
}

五、SharedPreferences多进程支持(虽然支持,但是还是不靠谱的,大量同时读写操作也会存在问题)

public static int getMode() {
    // MODE_MULTI_PROCESS is always on in apps targeting Gingerbread
    // (Android 2.3) and below, and off by default in later versions
    return Build.VERSION.SDK_INT > 8 ? 4 : 0;
}
   
public void test() {
    SharedPreferences settings = context.getSharedPreferences("fileName", getMode());
}

下面是getSharedPreferences方法的定义和解释:

public abstract SharedPreferences getSharedPreferences (String name, int mode)

Added in API level 1

Retrieve and hold the contents of the preferences file 'name', returning a SharedPreferences through which you can retrieve and modify its values. Only one instance of the SharedPreferences object is returned to any callers for the same name, meaning they will see each other's edits as soon as they are made.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java成长之路

代码块总结

这种形式的程序段我们将其称之为代码块,所谓代码块就是用大括号({})将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法。一般来说代码块是不能单独运行...

894
来自专栏PHP实战技术

你应该这个姿势学习php(3)

输出缓冲区的内容,如果你想获取缓冲区的内容要在这个函数之前使用ob_get_contents(),不然数据将会被清空

42114
来自专栏老马说编程

(16) 继承的细节

上节我们介绍了继承和多态的基本概念,基本概念是比较简单的,子类继承父类,自动拥有父类的属性和行为,并可扩展属性和行为,同时,可重写父类的方法以修改行为。 但继承...

1819
来自专栏程序员互动联盟

【java基础】匿名类

昨天后台的一个小伙伴提到了,java里面的匿名类,这个概念在平常java码代码的时候用的特别多,所以找了一篇介绍表述比较清晰的文章分享给大家,能极大的简化代码量...

3477
来自专栏哲学驱动设计

GIX4中懒加载

在使用OpenExpressApp框架的GIX4项目中,对象的懒加载按照对象的性质不同,分为以下两种方式: 根对象类:     Get方法:获取根对象,并附带上...

1808
来自专栏于晓飞的专栏

Java I/O 总结

Java I/O的的架构使用了装饰器的模式,我们在使用流的时候需要新建很多的装饰器对象,对源数据进行层层包装。各个包装类名以及它们的应用场景比较多,初学的时候难...

843
来自专栏码云1024

C#委托与事件

3546
来自专栏Android小菜鸡

解决运动单例造成Fragment状态被保留的问题

  其实Activiyt、Fragment都是重新构建了的。不过由于对BottomSelectView采取单例构建数据的方式。如果对构建数据做了null判断。第...

561
来自专栏GreenLeaves

Array对象的判定

/* 关于JS对象类型的判断,最复杂的在于RegExp和Array了,判定RegExp的情形不较少,而Array就比较多了,下面就是判断Array的...

1675
来自专栏Java技术栈

类、变量、块、构造器、继承初始化顺序,终极解答。

最近发现微信群里面有些群友在讨论类的初始化顺序,如类的静态变量、成员变量、静态代码块、非静态代码块、构造器,及继承父类时,它们的初始化顺序都是怎样的,下面我通过...

2644

扫码关注云+社区