美文网首页
SharedPreferences的apply和commit的区

SharedPreferences的apply和commit的区

作者: 业精于勤_荒于嬉 | 来源:发表于2023-06-30 18:49 被阅读0次
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()方法。

参考:每日一问:SharedPreferences 的 apply() 和 commit()

相关文章

网友评论

      本文标题:SharedPreferences的apply和commit的区

      本文链接:https://www.haomeiwen.com/subject/rwfzydtx.html