public interface Editor {
.....省略部分代码....
boolean commit();
void apply();
}
由上面代码可以看出,SharedPreferences的内部类Editor提供了两种提交方式:commit()和apply()。
我们再来看下,在SharedPreferencesNewImpl类中二者的具体实现:
public final boolean commit() {
SharedPreferencesNewImpl.this.save(this, false, true, false);
return true;
}
public final void apply() {
SharedPreferencesNewImpl.this.save(this, false, false, true);
}
可以看到二者都调用了SharedPreferencesNewImpl的save方法,前两个传参一样,后两个参数的传参不一样,我们看下SharedPreferencesNewImpl的save方法:
private void save(Editor var1, boolean var2, boolean var3, boolean var4) {
if (var1 != null) {
synchronized(this.mMap) {
this.mCurTryTime = 0;
boolean var6 = true;
if (!this.merge(var1, this.mMap, false)) {
var6 = false;
if (this.mEditorList.size() == 0) {
return;
}
}
if (var6) {
this.mEditorList.add(var1);
}
}
if (var3) {
this.saveInner(var2);
} else {
long var5 = var4 ? 1000L : 0L;
this.mSaveRunnable.setArg(var2);
Message var8;
(var8 = Message.obtain(this.mHandler, this.mSaveRunnable)).what = 21310;
this.mHandler.sendMessageDelayed(var8, var5);
}
}
}
由上面代码可以看出当var3为true(commit方式提交)时,直接调用了saveInner保存到磁盘,如果var3为false(apply方式提交)时,通过mHandler发送了个Message消息。我们再看下这个mHandler:
this.mHandler = new Handler(this.getHandlerThread().getLooper());
可以看到这里用的是HandlerThread当中的looper,其实是个子线程的looper,所以这里就知道了,apply方式提交时,其实是启动了子线程去提交到硬盘。
总结
1、apply()没有返回值。而commit()返回boolean类型的返回值,表明修改是否提交成功。
2、commit()是把修改提交到硬盘的。而apply()先立即把修改提交到内存,然后通过HandlerThread开启一个异步线程提交到硬盘,并且如果提交失败,不会收到任何通知。
3、commit()提交是同步过程,效率会比apply()异步提交的慢,在不关心提交结果是否成功的情况下,优先考虑apply()方法
4、apply()是使用异步线程写入磁盘,commit()是同步写入磁盘。所以我们在主线程中使用commit()的时候,需要考虑是否会出现ANR问题。
5、我们每次添加键值对的时候,都会重新写入整个文件的数据,所以它不适合大量数据存储。
6、多线程场景下效率比较低,因为get操作的时候,会锁定SharedPreferences里面的对象,互斥其他操作,而当put、commit()和apply()操作的时候都会锁住Editor对象,在这样的情况下,效率会降低。
7、由于每次都会把整个文件加载到内存中,因此,如果SharedPreferences文件过大,或者在其中的键值对是大对象的JSON数据则会占用大量内存,读取较慢是一方面,同时也会引发程序频繁GC,导致界面的卡顿。
基于以上缺点的优化
1、建议不要存储大数据到SharedPreferences,也不要把较多的数据存储到同一个name对应的SharedPreferences中,最好根据规则拆分成多个SharedPreferences文件。
2、频繁修改的数据修改后同一提交,而不是修改过后马上提交
3、在跨进程通信中不去使用SharedPreferences。
4、获取SharedPreferences对象的时候会读取SharedPreferences文件,如果文件没有读取完,就执行了get和put操作,可能会出现需要等待的情况,因此最好提前获取SharedPreferences对象。
5、每次调用edit()方法都会创建一个新的EditorImpl对象,不要频繁调用edit()方法。
网友评论