SharedPreferences是一种轻型的Android数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。它的存储位置是在/data/data/<包名>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。比较经典的使用方式例如用户输入框对过往登录账户的存储。实现SharedPreferences存储的步骤如下:
1、根据Context获取SharedPreferences对象
2、利用edit()方法获取Editor对象。
3、通过Editor对象存储key-value键值对数据。
4、通过commit()或apply()方法提交数据。
那么问题来了,commit和apply到底有什么区别呢,或者说我们如何选择?
总结一下:
commit() 是直接同步地提交到硬件磁盘,因此,多个并发的采用 commit() 做提交的时候,它们会等待正在处理的 commit() 保存到磁盘后再进行操作,从而降低了效率。而 apply() 只是原子的提交到内容,后面再调用 apply() 的函数进行异步操作。
翻源码可以发现 apply() 返回值为 void,而 commit() 返回一个 boolean 值代表是否提交成功。
apply() 方法不会有任何失败的提示。
但使用apply()就真的完美无缺吗。非也
上面说到,commit是直接同步地提交到硬件磁盘,apply只是原子的提交到内容,后面再调用 apply() 的函数进行异步操作。这里的后面,其实是在Activity的onPause的时候去执行,这个时候会有一个问题。我们知道,Activity跳转的时候,比如ActivityA跳转到ActivityB,那么两个Activity的生命周期是:A(onPause)-B(onCreat)-B(onStart)-B(onResume)-A(onStop)。如果我们在ActivityA的onPause中做了耗时操作,将会导致Activity跳转卡顿严重,甚至ANR。
也许有童鞋会说,sp的加载不是在子线程么,怎么会卡住主线程?子线程IO就一定不会阻塞主线程吗?
sp为了避免同时读写,在操作的时候挂了一把锁
private void awaitLoadedLocked() {
while (!mLoaded) {
try {
wait();
} catch (InterruptedException unused) {
}
}
}
这意味着,apply虽然开了子线程处理,但是activity退出时会等待写入完成 也可能造成anr。
所以,我们在使用SP的时候,一定要仔细斟酌。不要滥用sp,非轻量级数据,尽量避免使用sp来存储。
而且在储存多对数据时,不要多次commit。对实时性要求不高的数据,尽量合并commit。避免如下错误写法:
SharedPreferences sp = getSharedPreferences("test", MODE_PRIVATE);
sp.edit().putString("test1", "sss").apply();
sp.edit().putString("test2", "sss").apply();
sp.edit().putString("test3", "sss").apply();
sp.edit().putString("test4", "sss").apply();
网友评论