Android数据存储之SharedPreferences详细总结

时间:2022-10-25 00:13:28

Android中常见的几种存储方式:

  1. SharedPreferences
  2. SQLite数据库存储
  3. 文件存储
  4. 网络存储

其中也许最常用的就是SharedPreferences存储和文件存储了,今天总结一下SharedPreferences。带着问题学习SharedPreferences:
问题:

  • 存储的位置是在哪
  • SharedPreferences存储的文件格式是什么
  • 如何查看
  • 创建的时候需要context,不同的context创建有没有区别
  • 创建的几种mode以及区别
  • apply和commit的区别
  • 存取数据使用多张表还是一张表

看完下面的讲解,你应该就能回答上面的问题了

google官方说明

SharedPreferences 类提供了一个通用框架,以便您能够保存和检索原始数据类型的永久性键值对。 您可以使用 SharedPreferences 来保存任何原始数据:布尔值、浮点值、整型值、长整型和字符串。 此数据将跨多个用户会话永久保留(即使您的应用已终止亦如此)。

要获取应用的 SharedPreferences 对象,请使用以下两个方法之一:

  • getSharedPreferences() - 如果您需要多个按名称(使用第一个参数指定)识别的首选项文件,请使用此方法。
  • getPreferences() - 如果您只需要一个用于 Activity 的首选项文件,请使用此方法。 由于这将是用于 Activity 的唯一首选项文件,因此无需提供名称。

我先在Activity A中写入

SharedPreferences settings = getSharedPreferences("test", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("num", 23);
System.out.println("-----------写入");

打印:
I/System.out: ———–写入

然后在Activity B中查看

SharedPreferences settings = getSharedPreferences("test", 0);
int num = settings.getInt("num", 0);
System.out.println("-----------num="+num);

打印:
I/System.out: ———–num=23

存储的位置是在哪

如果你使用的是3.0以前的Android studio版本,可以在通过DDMS的【File Explorer】中查看,如果你使用的是3.0以及以后的Android studio版本,可以直接通过一下步骤打开

点击 View > Tool Windows > Device File Explorer 或工具窗口栏中的 Device File Explorer 按钮以打开设备文件浏览器。

注意需要用模拟器查看,手机没有root是看不到的

Android数据存储之SharedPreferences详细总结

找到data\data\程序包名\shared_prefs目录,你会发现你刚创建的文件
Android数据存储之SharedPreferences详细总结

SharedPreferences存储的文件格式是什么

Android数据存储之SharedPreferences详细总结
我想你应该也看到了是xml文件
内容是:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <int name="num" value="23" />
</map>

如何查看

如果是开发上面就是查看过程,如果是真机需要把手机root,才有权限查看

创建的时候需要context,不同的context创建有没有区别

我是在不同的Activity中写入和查看的,但是操作的是同一个test.xml,所以不同的Context操作只要getSharedPreferences(“test”, 0);获取SharedPreferences时传入的第一个参数name相同就得到是相同的SharedPreferences,操作的是同一个xml文件。

那么如何获取一个Activity单独的SharedPreferences呢?Google已经说了

getPreferences() - 如果您只需要一个用于 Activity 的首选项文件,请使用此方法。 由于这将是用于 Activity 的唯一首选项文件,因此无需提供名称

可以查看源码,其实就是获取了当前Activity的ClassName,所以这个name是单独的,所以产生的也是用于 此Activity 的唯一首选项文件

/**
     * Retrieve a {@link SharedPreferences} object for accessing preferences
     * that are private to this activity.  This simply calls the underlying
     * {@link #getSharedPreferences(String, int)} method by passing in this activity's
     * class name as the preferences name.
     *
     * @param mode Operating mode.  Use {@link #MODE_PRIVATE} for the default
     *             operation.
     *
     * @return Returns the single SharedPreferences instance that can be used
     *         to retrieve and modify the preference values.
     */
    public SharedPreferences getPreferences(@Context.PreferencesMode int mode) {
 return getSharedPreferences(getLocalClassName(), mode);
    }

创建时的几种mode以及区别

上面获取SharedPreferences的时候我直接使用的是getSharedPreferences(“test”, 0),第二个参数传入的是0,代表操作模式是MODE_PRIVATE
操作模式有以下几种:

  1. MODE_PRIVATE
  2. MODE_WORLD_READABLE
  3. MODE_WORLD_WRITEABLE
  4. MODE_APPEND
  5. MODE_MULTI_PROCESS

Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容, 而不是擦除以前的,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取。
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

以上是我看的网上的说法,但是我在最新的Android Studio上开发,也就是在Android Studio3.1上去看到了下面的场景:
Android数据存储之SharedPreferences详细总结

MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE和MODE_MULTI_PROCESS都被废弃了

然后我又试了下MODE_APPEND,又给了我以下的提示:
Must be one or more of: Context.MODE_PRIVATE, Context.MODE_WORLD_READABLE, Context.MODE_WORLD_WRITEABLE, Context.MODE_MULTI_PROCESS less… (⌘F1)

看来目前能用的只能是MODE_PRIVATE了,其他的不用考虑了

apply和commit的区别

先看看两者的说明:

/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing.  This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call commit wins.
*
* <p>If you don't care about the return value and you're
* using this from your application's main thread, consider
* using {@link #apply} instead.
*
* @return Returns true if the new values were successfully written
* to persistent storage.
*/
boolean commit();

1,commit方法是有一个boolean的返回值
2,当数据变化进行存储时是一个原子性的操作
3,当两个editor对象同时对一个共享的preferences参数进行操作时,永远都是最后一个调用commit方法的editor变更了最后的数据值


/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing.  This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures.  If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk.  The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly.  However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/
void apply();

1,apply方法是没有返回值的
2,当两个editor同时对preferences对象编辑时,也是最后一个调用apply方法的对象编辑数据
3,apply的提交操作也是原子性的

以上是我直接参考了这篇博客的结论:https://www.jianshu.com/p/c8d10357c939

其实我们Android studio的很强大,当你使用editor.commit();的时候直接推荐你使用apply,commit直接写入持久化内存,apply在后台处理它

Consider using apply() instead; commit writes its data to persistent storage immediately, whereas apply will handle it in the background

他们的区别总结:
apply()没有返回值,commit()有返回值,在不关心结果的时候推荐使用apply()
commit()直接写入持久化内存,是同步过程,速度比apply()慢,apply()是异步的提交,速度更快

存取数据使用多张表还是一张表

我们知道SharedPreferences存储的格式是xml,既然是xml就要用到解析,只不过这个解析过程我们是看不到的也不需要去关心,但是解析的速度却会影响到我们的用户体验,加入一张表里面有很多数据,比如你把一个页面的数据存起来了,数据量比较大,那么这个时候推荐为这些数据单独建立一个表,也就是推荐不同的数据放不同的表里面,防止所有数据都放在一张表里面一次读取要耗费很长时间

参考链接:
https://www.jianshu.com/p/c8d10357c939