傻傻分不清楚系列(一):SharedPreferences的commit和apply方法

一、简介

在开发中,很多重要的瞬时数据都需要保存起来让数据持久化,即 Android 中的数据持久化技术。相信这个对于大家来说并不陌生,常用的如文件存储、数据库存储、SharedPreferences ,以及网络存储等。今天要介绍的便是其中之一的 SharedPreferences 。

SharedPreferences 是一个轻量级的存储类,常用于保存软件配置参数、账号和密码等。SharedPreferences 内部使用 xml 文件将数据以 key...value 的格式保存在 “\data\data\应用程序包名\shared_prefs\” 目录下,在 Android Studio 中打开 Device File Explorer 即可查看。下图是 SharedPreferences 可以保存的数据类型。


SharedPreferences可保存的数据类型

接下来是实践时间,分别介绍利用 SharedPreferences 存数据和取数据的方法。

二、用法

(一)SharedPreferences 存数据

  1. 获取 SharedPreferences 对象。Android 中提供了三种方法获取 SharedPreferences 对象:
  • Context 类中的 getSharedPreferences() 方法
/**
* Activity中直接getSharedPreferences,Fragment中需要getActivity().getSharedPreferences
* 参数一:SharedPreferences文件名
* 参数二:操作模式,Android6.0之后仅MODE_PRIVATE一种模式可选,表示只有当前应用程序才能对参数①中的文件进行读写
*/
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
  • Activity 类中的 getPreferences() 方法
/**
* Activity中直接getPreferences,Fragment中需要getActivity().getPreferences()
* 参数:操作模式(此种方式获取SharedPreferences对象时会自动使用当前Activity的类名作为文件名,所以只需一个参数)
*/
SharedPreferences sp = getPreferences(MODE_PRIVATE);
  • PreferencesManager 类中的 getDefaultSharedPreferences() 方法
/**
* PreferenceManager类的静态方法,自动使用当前应用程序包名作为前缀来命名SharedPreferences文件,操作模式自动为MODE_PRIVATE
* 参数:上下文
*/
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);


  1. 调用 SharedPreferences 对象的 edit() 方法获取 SharedPreferences.Editor 对象:
SharedPreferences.Editor editor = sp.edit();


  1. 调用 SharedPreferences.Editor 对象的 putXXX() 方法添加需要保存的数据:
Set<String> userInfo = new HashSet<>();
userInfo.add("张三");
userInfo.add("20");
        
editor.putString("name", "张三");
editor.putBoolean("isAdult", true);
editor.putFloat("height", 178.00F);
editor.putInt("age", 20);
editor.putLong("IDNum", 123456789000L);
editor.putStringSet("user", userInfo);


  1. 调用 SharedPreferences.Editor 对象的 apply() 方法或者 commit() 方法提交刚刚添加的数据:
//两种提交方式都可以,任选其一即可
editor.apply();
editor.commit();



至此,利用 SharedPreferences 存储数据的方法就介绍完了,下面是完整实例:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        Set<String> userInfo = new HashSet<>();
        userInfo.add("张三");
        userInfo.add("20");
        editor.putString("name", "张三");
        editor.putBoolean("isAdult", true);
        editor.putFloat("height", 178.00F);
        editor.putInt("age", 20);
        editor.putLong("IDNum", 123456789000L);
        editor.putStringSet("userInfo", userInfo);
        editor.apply();
    }
}

运行程序以后,数据就已经保存成功了,眼见为实,在 Android Studio 中打开 Device File Explorer ,进入 “\data\data\应用程序包名\shared_prefs\” 目录下,结果如下:


Device File Explorer 中查看到的结果



(二)SharedPreferences 取数据

  1. 获取 SharedPreferences 对象。利用 SharedPreferences 存数据时已经介绍过了获取 SharedPreferences 对象的方法,这里不再赘述,直接看代码:
/**
* 参数一:SharedPreferences文件名,必须和存数据时的文件名一致,存什么就取什么
* 参数二:操作模式
*/
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);


  1. 调用 SharedPreferences 对象的 getXXX() 方法,根据存数据时约定的 key 值获取对应的数据:
/**
* SharedPreferences对象的.getXXX()方法接收两个参数,该方法有返回值,返回key对应的value
* 参数一:存储数据时使用的key
* 参数二:默认值,如果取值失败则返回默认值
*/
String name = sp.getString("name", "");
boolean isAdult = sp.getBoolean("isAdult", false);
float height = sp.getFloat("height", 0F);
int age = sp.getInt("age", 0);
long IDNum = sp.getLong("IDNum", 0L);
HashSet<String> userInfo = (HashSet<String>) sp.getStringSet("userInfo", new HashSet<String>());



至此,利用 SharedPreferences 取出数据的方法就介绍完了,下面是完整实例:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
        String name = sp.getString("name", "");
        boolean isAdult = sp.getBoolean("isAdult", false);
        float height = sp.getFloat("height", 0F);
        int age = sp.getInt("age", 0);
        long IDNum = sp.getLong("IDNum", 0L);
        HashSet<String> userInfo = (HashSet<String>) sp.getStringSet("userInfo", new HashSet<String>());
        Log.d("MyLog", "姓名:" + name);
        Log.d("MyLog", "是否成年:" + isAdult);
        Log.d("MyLog", "身高:" + height);
        Log.d("MyLog", "年龄:" + age);
        Log.d("MyLog", "身份证号码:" + IDNum);
        Log.d("MyLog", "用户信息:" + userInfo.toString());
    }
}

运行程序后,Logcat 打印的日志结果如下:

SharedPreferences 取出的数据


三、apply 与 commit 的区别

  1. 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();

如上是 Editor.commit 方法的源码,英文好一点的童鞋能从源码注释中了解不少东西,英语差点的童鞋不要着急,这里我提取出源码注释中的一些关键信息,如下:

  • commit 方法用于将需要保存的数据通过 Editor 提交并保存到 SharedPreferences 对象中;
  • commit 提交过程属于原子操作,也就是该提交过程不可中断,要么全部提交成功,要么全部提交失败,不会出现只保存了其中一部分数据的情况;
  • 同一个 SharedPreferences 对象,多次调用 commit 方法,最后一次的调用会覆盖掉前面提交的数据,也就是当出现多次 commit 时,以最后一次 commit 提交的数据为准;
  • commit 方法有返回值( boolean 类型),意思是如果本次写入数据成功,返回 true,否则返回 false 。
  • 如果不关心返回值(不关心数据是否写入成功),推荐使用 apply 方法提交数据。

  1. apply
/**
 * 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();

如上是 Editor.apply 方法的源码,这里,我照例提取出该方法的源码注释中的关键信息,如下:

  • 跟 commit 方法一样,apply 方法用于将需要保存的数据通过 Editor 提交并保存到 SharedPreferences 对象中;
  • 跟 commit 方法一样,同一个 SharedPreferences 对象,多次调用 apply 方法,最后一次的调用会覆盖掉前面提交的数据,也就是当出现多次 apply 时,以最后一次 apply 提交的数据为准;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容