设为首页 加入收藏

TOP

细数 SharedPreferences 的那些槽点 !(五)
2019-09-03 03:44:48 】 浏览:190
Tags:细数 SharedPreferences 那些
)) { Object existingValue = mapToWriteToDisk.get(k); if (existingValue != null && existingValue.equals(v)) { continue; } } mapToWriteToDisk.put(k, v); } changesMade = true; if (hasListeners) { keysModified.add(k); } } mModified.clear(); if (changesMade) { mCurrentMemoryStateGeneration++; } memoryStateGeneration = mCurrentMemoryStateGeneration; } } return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners, mapToWriteToDisk); }

简单说,commitToMemory() 方法会将所有需要改动的数据 mModified 和原 sp 文件数据 mMap 进行合并生成一个新的数据集合 mapToWriteToDisk,从名字也可以看出来,这就是之后要写入文件的数据集。没错,SharedPreferences 的写入都是全量写入。即使你只改动了其中一个配置项,也会重新写入所有数据。针对这一点,我们可以做的优化是,将需要频繁改动的配置项使用单独的 sp 文件进行存储,避免每次都要全量写入。

3.2.3 enqueueDiskWrite()

> SharedPreferencesImpl.java

private void enqueueDiskWrite(final MemoryCommitResult mcr,
                                final Runnable postWriteRunnable) {
    final boolean isFromSyncCommit = (postWriteRunnable == null);

    final Runnable writeToDiskRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (mWritingToDiskLock) {
                writeToFile(mcr, isFromSyncCommit); // 见 3.2.3.1
            }
            synchronized (mLock) {
                mDiskWritesInFlight--;
            }
            if (postWriteRunnable != null) {
                postWriteRunnable.run();
            }
        }
    };

    // Typical #commit() path with fewer allocations, doing a write on
    // the current thread.
    // commit() 直接在当前线程进行写入操作
    if (isFromSyncCommit) {
        boolean wasEmpty = false;
        synchronized (mLock) {
            wasEmpty = mDiskWritesInFlight == 1;
        }
        if (wasEmpty) {
            writeToDiskRunnable.run();
            return;
        }
    }

    // apply() 方法执行此处,由 QueuedWork.QueuedWorkHandler 处理
    QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);
}

回头先看一下 commit() 方法中是如何调用 enqueueDiskWrite() 方法的:

 SharedPreferencesImpl.this.enqueueDiskWrite(mcr, null);

第二个参数 postWriteRunnablenull,所以 isFromSyncCommittrue,会执行上面的 if 代码块,而不执行 QueuedWork.queue()。由此可见,commit() 方法最后的写文件操作是直接在当前调用线程执行的,你在主线程调用该方法,就会直接在主线程进行 IO 操作。显然,这是不建议的,可能造成卡顿或者 ANR。在实际使用中我们应该尽量使用 apply() 方法来提交数据。当然,apply() 也并不是十全十美的,后面我们会提到。

3.2.3.1 writeToFile()

commit() 方法的最后一步了,将 mapToWriteToDisk 写入 sp 文件。

> SharedPreferencesImpl.java

private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) {
        long startTime = 0;
        long existsTime = 0;
        long backupExistsTime = 0;
        long outputStreamCreateTime = 0;
        long writeTime = 0;
        long fsyncTime = 0;
        long setPermTime = 0;
        long fstatTime = 0;
        long deleteTime = 0;

        if (DEBUG) {
            startTime = System.currentTimeMillis();
        }

        boolean fileExists = mFile.exists();

        if (DEBUG) {
            existsTime = System.currentTimeMillis();

            // Might not be set, hence init them to a default value
            backupExistsTime = existsTime;
        }

        // Rename the current file so it may be used as a backup during the next read
        if (fileExists) {
            boolean needsWrite = false;

            // Only need to write if the disk state is older than this commit
            // 仅当磁盘状态比当前提交旧时草需要写入文件
            if (mDiskStateGeneration < mcr.memoryStateGeneration) {
                if (isFromSyncCommit) {
                    needsWrite = true;
                } else {
                    synchronized (mLock) {
                        // No need to persist intermediate states. Just wait for the latest state to
                        // be persisted.
                        if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) {
                            needsWrite = true;
                        }
                    }
                }
            }

            if (!needsWrite) { // 无需写入,直接返回
                mcr.setDiskWriteResult(false, true);
                return;
            }

            boolean backupFileExists = mBackupFile.exists(); // 备份文件是否存在

            if (DEBUG) {
                backupExistsT
首页 上一页 2 3 4 5 6 7 下一页 尾页 5/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Android四大组件之Service 下一篇亲,麻烦给个五星好评!—RatingB..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目