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

对于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区别,如有写不对的地方,欢迎各位指正,多谢!

    原文作者:_pitter
    原文地址: https://blog.csdn.net/wangpingtaohn/article/details/75159495
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞