从源码角度分析sharedPreferences的commit()与apply()的区别

来源:互联网 发布:mac 更改用户照片 编辑:程序博客网 时间:2024/05/22 03:12

对于Android开发者来说,对于sharedPreferences并不陌生,用于存储轻量级的数据,而存储的时候,会用到Editor,在API 9之前,提交的时候用用到了editor.commit()方法,而从API 9之后,新增了一个apply()方法,可能大家多多少少知道它是一个异步的提交,能提高IO性能。
而本篇文章主要就是从源码去分析,它是如何提高IO性能的。废话不多说,上代码,跟进代码大家看到,sharedPreferences只是一个接口,所有的实现逻辑都在它的实现类sharedPreferencesImpl里,首先看下commit()方法,看代码解释:

public boolean commit() {            MemoryCommitResult mcr = commitToMemory();//把数据提交到内存            SharedPreferencesImpl.this.enqueueDiskWrite(                mcr, null /* sync write on this thread okay */);            try {                mcr.writtenToDiskLatch.await();            } catch (InterruptedException e) {                return false;            }            notifyListeners(mcr);            return mcr.writeToDiskResult;        }
public void apply() {            final MemoryCommitResult mcr = commitToMemory();//把数据提交到内存            final Runnable awaitCommit = new Runnable() {                    public void run() {                        try {                            mcr.writtenToDiskLatch.await();                        } catch (InterruptedException ignored) {                        }                    }                };            QueuedWork.add(awaitCommit);            Runnable postWriteRunnable = new Runnable() {                    public void run() {                        awaitCommit.run();                        QueuedWork.remove(awaitCommit);                    }                };            SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);            // Okay to notify the listeners before it's hit disk            // because the listeners should always get the same            // SharedPreferences instance back, which has the            // changes reflected in memory.            notifyListeners(mcr);        }

比较两个方法,首先都是先把数据同步提交到内存中,然后再执行下面的SharedPreferencesImpl.this.enqueueDiskWrite方法,而两个方法调用不同的地方是,commit第二个参数传进去是null,apply传进去的是postWriteRunnable。咱们看下enqueueDiskWrite()这个方法里面是怎么执行的。

 private void enqueueDiskWrite(final MemoryCommitResult mcr,final Runnable postWriteRunnable) {        final Runnable writeToDiskRunnable = new Runnable() {                public void run() {                    synchronized (mWritingToDiskLock) {                        writeToFile(mcr);                    }                    synchronized (SharedPreferencesImpl.this) {                        mDiskWritesInFlight--;                    }                    if (postWriteRunnable != null) {                        postWriteRunnable.run();                    }                }            };        final boolean isFromSyncCommit = (postWriteRunnable == null);        // Typical #commit() path with fewer allocations, doing a write on        // the current thread.        if (isFromSyncCommit) {            boolean wasEmpty = false;            synchronized (SharedPreferencesImpl.this) {                wasEmpty = mDiskWritesInFlight == 1;            }            if (wasEmpty) {                writeToDiskRunnable.run();                return;            }        }        QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);    }

首先这个方法里先new 一个Runnable writeToDiskRunnable (注意这里,只是一个Runnbale,而不是new Thread/一个子线程,有部分同学可能看到Runnable以为就是一个子线程呢),然后这个writeToDiskRunnable的run方法里执行writeToFile的方法,就是正在的要写到sp文件的方法了。接着往下看,isFromSyncCommit变量,它就是跟着commit与apply传进来的postWriteRunnable是否为空判断的,所以这当是commit方法调用是,isFromSyncCommit为true,apply方法调用时,isFromSyncCommit为false,所以当isFromSyncCommit为true并且mDiskWritesInFlight为1时(commitToMemory赋值的),就在当前的线程里执行了writeToDiskRunnable 的writeToFile方法了,也就是说当commit()方法调用的时候,是在当前线程执行的,串行执行。当apply()方法调用的时候,直接把writeToDiskRunnable 添加到QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);队列中执行,也就是异步执行,所以说apply相对commit能提交IO性能。

好了,以上就是自己从源码角度去分析SharedPreferences的commit与apply区别,如有写不对的地方,欢迎各位指正,多谢!

原创粉丝点击