SharedPreferences源码剖析

栏目: 编程语言 · XML · 发布时间: 6年前

内容简介:首先获取在

一、概述

1.1 简介

1.2 用法

首先获取 SharedPreferences 实例,调用 sp.edit() 获得可编辑实例,写入类型的数据并提交。

SharedPreferences sp = getSharedPreferences("PrefsName", MODE_PRIVATE);

SharedPreferences.Editor editor = sp.edit();
editor.putInt("Int", 1024);
editor.putLong("Long", 47526348576L);
editor.putFloat("Float", 3.1415926F);
editor.putBoolean("Boolean", true);
editor.putString("String", "SharedPreferences String");
editor.apply();

Android Studio 右下角有 Device File Explorer ,按照以下路径找出保存的 <PrefsName>.xml 。文件名为 getSharedPreferences("PrefsName", MODE_PRIVATE) 中的实参值。

/data/data/<Application Package Name>/shared_prefs/<PrefsName>.xml

实际写入的文件内容是这样的:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <int name="Int" value="1024" />
    <float name="Float" value="3.1415925" />
    <boolean name="Boolean" value="true" />
    <long name="Long" value="47526348576" />
    <string name="String">SharedPreferences String</string>
</map>

简单看来,除了String类型的其他类型值实际上都保存为字符串。

1.3 架构

二、源码剖析

2.1 SharedPreferences抽象接口

SharedPreferences 是一个接口,源码路径是 /frameworks/base/core/java/android/content

// 读写由getSharedPreferences返回的数据。修改操作需通过Editor对象,以保证数据一致性和控制回写的时机
// 此类不能用在多进程中,可以在相同进程不同线程中同时调用线程安全
public interface SharedPreferences {

    // 当SharedPreference发生变化时回调的监听器
    public interface OnSharedPreferenceChangeListener {
        // 当SharedPreference发生修改、新增、移除时回调的方法,key为此时变化的键,方法回调在主线程
        // @param sharedPreferences 发生变化的SharedPreferences
        // @param key               值发生修改、新增、移除的键
        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
    }

    // 修改SharedPreferences中值的接口,所有操作均为批处理,只在调用commit或apply后才回写到磁盘
    public interface Editor {
        // 向编辑器设置一个String类型的键值对,并在commit或apply方法调用时进行回写
        Editor putString(String key, @Nullable String value);

        // 向编辑器设置一个String类型的键值对集合,并在commit或apply方法调用时进行回写
        Editor putStringSet(String key, @Nullable Set<String> values);
        
        // 向编辑器设置一个int类型的键值对,并在commit或apply方法调用时进行回写
        Editor putInt(String key, int value);
        
        // 向编辑器设置一个long类型的键值对,并在commit或apply方法调用时进行回写
        Editor putLong(String key, long value);
        
        // 向编辑器设置一个float类型的键值对,并在commit或apply方法调用时进行回写
        Editor putFloat(String key, float value);
        
        // 向编辑器设置一个boolean类型的键值对,并在commit或apply方法调用时进行回写
        Editor putBoolean(String key, boolean value);

        // 移除编辑器中指定的key,并在commit或apply方法调用时进行回写
        // 移除操作在其他操作之前,即不管移除操作是否在添加之后调用,都会优先执行
        Editor remove(String key);

        // 清除所有值,并在commit或apply方法调用时进行回写
        // 移除操作在其他操作之前,即不管移除操作是否在添加之后调用,都会优先执行
        Editor clear();

        // 执行所有preferences修改
        // 当有两个editors同时修改preferences,最后一个被调用的总能被执行
        // 如果不关心执行的结果值,且在主线程使用,建议通过apply提交修改
        // true提交并修改成功,false表示失败
        boolean commit();

        // 执行所有preferences修改
        // 当有两个editors同时修改preferences,最后一个被调用的总能被执行
        // apply所有提交保存在内存中,并异步进行回写,即回写失败不会有任何提示
        // 当apply还没完成,其他editor的commit操作会阻塞并等待异步回写完成
        // SharedPreferences进程内线程安全,且在不关心返回值的情况下可用apply代替commit
        // apply的写入安全由Android Framework保证,不受组件生命周期或交互影响
        void apply();
    }

    // 从preferences获得所有值,且一定不能修改这个Map的数据,增删改都不行
    // 否则会出现已存储数据不一致的问题
    Map<String, ?> getAll();

    // 获取key对应的String,若key不存在则返回defValue
    // 如果key存在但不是String类型,则直接抛出ClassCastException
    @Nullable
    String getString(String key, @Nullable String defValue);
    
    // 通过key获取字符串集合,且一直能够不能修改返回的数据,否则会导致数据不一致的问题
    @Nullable
    Set<String> getStringSet(String key, @Nullable Set<String> defValues);
    
    // 获取key对应的int,若key不存在则返回defValue
    // 如果key存在但不是int类型,则直接抛出ClassCastException
    int getInt(String key, int defValue);
    
    // 获取key对应的long,若key不存在则返回defValue
    // 如果key存在但不是long类型,则直接抛出ClassCastException
    long getLong(String key, long defValue);
    
    // 获取key对应的float,若key不存在则返回defValue
    // 如果key存在但不是float类型,则直接抛出ClassCastException
    float getFloat(String key, float defValue);

    // 获取key对应的boolean,若key不存在则返回defValue
    // 如果key存在但不是boolean类型,则直接抛出ClassCastException
    boolean getBoolean(String key, boolean defValue);

    // 检查是否已包含此键代表的preference
    boolean contains(String key);

    // 给preferences创建多一个新的Editor,并使用commit提交修改
    Editor edit();
    
    // 新增一个未注册的监听器
    void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
    
    // 移除一个已注册的监听器
    void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}

2.2 SharedPreferencesImpl实现类

类文件在 /frameworks/base/core/java/android/app

final class SharedPreferencesImpl implements SharedPreferences {
    private static final String TAG = "SharedPreferencesImpl";
    private static final boolean DEBUG = false;
    private static final Object CONTENT = new Object();

    /** If a fsync takes more than {@value #MAX_FSYNC_DURATION_MILLIS} ms, warn */
    private static final long MAX_FSYNC_DURATION_MILLIS = 256;

    // Lock ordering rules:
    //  - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock
    //  - acquire mWritingToDiskLock before EditorImpl.mLock

    // 当前的文件
    private final File mFile;
    // 备份的文件
    private final File mBackupFile;
    // 模式
    private final int mMode;
    // 锁
    private final Object mLock = new Object();
    // 磁盘写入锁
    private final Object mWritingToDiskLock = new Object();

    @GuardedBy("mLock")
    private Map<String, Object> mMap;

    @GuardedBy("mLock")
    private int mDiskWritesInFlight = 0;
    
    // 已加载标志位
    @GuardedBy("mLock")
    private boolean mLoaded = false;

    @GuardedBy("mLock")
    private StructTimespec mStatTimestamp;

    @GuardedBy("mLock")
    private long mStatSize;
    
    // 监听器列表,通过WeakHashMap持有监听器
    @GuardedBy("mLock")
    private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
            new WeakHashMap<OnSharedPreferenceChangeListener, Object>();

    // 当前内存状态,持续递增
    @GuardedBy("this")
    private long mCurrentMemoryStateGeneration;

    // 提交到磁盘的最新内存状态
    @GuardedBy("mWritingToDiskLock")
    private long mDiskStateGeneration;

    // 系统文件同步请求的次数
    @GuardedBy("mWritingToDiskLock")
    private final ExponentiallyBucketedHistogram mSyncTimes = new ExponentiallyBucketedHistogram(16);
    private int mNumSync = 0;

    SharedPreferencesImpl(File file, int mode) {
        mFile = file;
        mBackupFile = makeBackupFile(file);
        mMode = mode;
        mLoaded = false;
        mMap = null;
        startLoadFromDisk();
    }

    // 开始从磁盘加载
    private void startLoadFromDisk() {
        synchronized (mLock) {
            mLoaded = false;
        }
        new Thread("SharedPreferencesImpl-load") {
            public void run() {
                loadFromDisk();
            }
        }.start();
    }

    private void loadFromDisk() {
        synchronized (mLock) {
            // 如果已经加载过,跳出
            if (mLoaded) {
                return;
            }
            // 备份文件存在,则把源文件删除,备份文件作为原文件
            if (mBackupFile.exists()) {
                mFile.delete();
                mBackupFile.renameTo(mFile);
            }
        }

        Map<String, Object> map = null;
        StructStat stat = null;
        try {
            stat = Os.stat(mFile.getPath());
            // 从文件读出数据
            if (mFile.canRead()) {
                BufferedInputStream str = null;
                try {
                    str = new BufferedInputStream(
                            new FileInputStream(mFile), 16*1024);
                    // 把xml转换为对应键值对
                    map = (Map<String, Object>) XmlUtils.readMapXml(str);
                } catch (Exception e) {
                    Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
                } finally {
                    IoUtils.closeQuietly(str);
                }
            }
        } catch (ErrnoException e) {
            /* ignore */
        }

        synchronized (mLock) {
            mLoaded = true;
            // 读取的数据不为空,则把数据设置到mMap
            if (map != null) {
                mMap = map;
                mStatTimestamp = stat.st_mtim;
                mStatSize = stat.st_size;
            } else {
                // 磁盘没有已保存数据,则创建空HashMap给mMap
                mMap = new HashMap<>();
            }
            mLock.notifyAll();
        }
    }
    
    // 创建备份文件
    static File makeBackupFile(File prefsFile) {
        return new File(prefsFile.getPath() + ".bak");
    }
    
    // 出现意外是开始重新加载
    void startReloadIfChangedUnexpectedly() {
        synchronized (mLock) {
            if (!hasFileChangedUnexpectedly()) {
                return;
            }
            startLoadFromDisk();
        }
    }

    // Has the file changed out from under us?  i.e. writes that
    // we didn't instigate.
    // 文件被外部操作修改了?
    private boolean hasFileChangedUnexpectedly() {
        synchronized (mLock) {
            if (mDiskWritesInFlight > 0) {
                // If we know we caused it, it's not unexpected.
                return false;
            }
        }

        final StructStat stat;
        try {
            /*
             * Metadata operations don't usually count as a block guard
             * violation, but we explicitly want this one.
             */
            BlockGuard.getThreadPolicy().onReadFromDisk();
            stat = Os.stat(mFile.getPath());
        } catch (ErrnoException e) {
            return true;
        }

        synchronized (mLock) {
            return !stat.st_mtim.equals(mStatTimestamp) || mStatSize != stat.st_size;
        }
    }
    
    // 注册修改监听器
    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        synchronized(mLock) {
            // 向列表中加入监听器
            mListeners.put(listener, CONTENT);
        }
    }
    
    // 移除修改监听器
    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        synchronized(mLock) {
            // 从列表中移除监听器
            mListeners.remove(listener);
        }
    }

    // 阻塞等待文件内容已加载到对象中
    private void awaitLoadedLocked() {
        if (!mLoaded) {
            // Raise an explicit StrictMode onReadFromDisk for this
            // thread, since the real read will be in a different
            // thread and otherwise ignored by StrictMode.
            BlockGuard.getThreadPolicy().onReadFromDisk();
        }
        while (!mLoaded) {
            try {
                mLock.wait();
            } catch (InterruptedException unused) {
            }
        }
    }
    
    // 获取所有
    @Override
    public Map<String, ?> getAll() {
        synchronized (mLock) {
            awaitLoadedLocked();
            //noinspection unchecked
            return new HashMap<String, Object>(mMap);
        }
    }

    // 获取字符串
    @Override
    @Nullable
    public String getString(String key, @Nullable String defValue) {
        synchronized (mLock) {
            awaitLoadedLocked();
            String v = (String)mMap.get(key);
            return v != null ? v : defValue;
        }
    }
    
    // 获取字符串集合
    @Override
    @Nullable
    public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
        synchronized (mLock) {
            awaitLoadedLocked();
            Set<String> v = (Set<String>) mMap.get(key);
            return v != null ? v : defValues;
        }
    }
    
    // 获取Int
    @Override
    public int getInt(String key, int defValue) {
        synchronized (mLock) {
            awaitLoadedLocked();
            Integer v = (Integer)mMap.get(key);
            return v != null ? v : defValue;
        }
    }
    
    // 获取Long
    @Override
    public long getLong(String key, long defValue) {
        synchronized (mLock) {
            awaitLoadedLocked();
            Long v = (Long)mMap.get(key);
            return v != null ? v : defValue;
        }
    }
    
    // 获取Float
    @Override
    public float getFloat(String key, float defValue) {
        synchronized (mLock) {
            awaitLoadedLocked();
            Float v = (Float)mMap.get(key);
            return v != null ? v : defValue;
        }
    }
    
    // 获取Boolean
    @Override
    public boolean getBoolean(String key, boolean defValue) {
        synchronized (mLock) {
            awaitLoadedLocked();
            Boolean v = (Boolean)mMap.get(key);
            return v != null ? v : defValue;
        }
    }
    
    // 检查时候包含指定key
    @Override
    public boolean contains(String key) {
        synchronized (mLock) {
            awaitLoadedLocked();
            return mMap.containsKey(key);
        }
    }

    @Override
    public Editor edit() {
        // 阻塞等待加载完成,并返回编辑对象
        synchronized (mLock) {
            awaitLoadedLocked();
        }

        return new EditorImpl();
    }

    // Return value from EditorImpl#commitToMemory()
    private static class MemoryCommitResult {
        final long memoryStateGeneration;
        @Nullable final List<String> keysModified;
        // SharedPreference修改时间监听器
        @Nullable final Set<OnSharedPreferenceChangeListener> listeners;
        // 需要写磁盘的Map
        final Map<String, Object> mapToWriteToDisk;
        final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
        
        // 写磁盘结果
        @GuardedBy("mWritingToDiskLock")
        volatile boolean writeToDiskResult = false;
        // 已写入标志位
        boolean wasWritten = false;

        private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
                @Nullable Set<OnSharedPreferenceChangeListener> listeners,
                Map<String, Object> mapToWriteToDisk) {
            this.memoryStateGeneration = memoryStateGeneration;
            this.keysModified = keysModified;
            this.listeners = listeners;
            this.mapToWriteToDisk = mapToWriteToDisk;
        }
        
        // wasWritten:已写入
        // result:结果
        void setDiskWriteResult(boolean wasWritten, boolean result) {
            this.wasWritten = wasWritten;
            writeToDiskResult = result;
            writtenToDiskLatch.countDown();
        }
    }

    public final class EditorImpl implements Editor {
        // 编辑器锁
        private final Object mEditorLock = new Object();
        
        // 需修改记录,记录在内存中
        @GuardedBy("mEditorLock")
        private final Map<String, Object> mModified = new HashMap<>();
        
        // 是否是干净的
        @GuardedBy("mEditorLock")
        private boolean mClear = false;
        
        // 存入String
        @Override
        public Editor putString(String key, @Nullable String value) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, value);
                return this;
            }
        }
        
        // 存入StringSet
        @Override
        public Editor putStringSet(String key, @Nullable Set<String> values) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key,
                        (values == null) ? null : new HashSet<String>(values));
                return this;
            }
        }
        
        // 存入Int
        @Override
        public Editor putInt(String key, int value) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, value);
                return this;
            }
        }
        
        // 存入Long
        @Override
        public Editor putLong(String key, long value) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, value);
                return this;
            }
        }
        
        // 存入Float
        @Override
        public Editor putFloat(String key, float value) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, value);
                return this;
            }
        }
        
        // 存入Boolean
        @Override
        public Editor putBoolean(String key, boolean value) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, value);
                return this;
            }
        }
        
        // 移除key
        @Override
        public Editor remove(String key) {
            synchronized (mEditorLock) {
                // 向HashMap记录最新修改
                mModified.put(key, this);
                return this;
            }
        }
        
        // 清空所有key
        @Override
        public Editor clear() {
            synchronized (mEditorLock) {
                // 设置清除标志位
                mClear = true;
                return this;
            }
        }

        @Override
        public void apply() {
            final MemoryCommitResult mcr = commitToMemory();
            final Runnable awaitCommit = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            mcr.writtenToDiskLatch.await();
                        } catch (InterruptedException ignored) {
                        }
                    }
                };

            QueuedWork.addFinisher(awaitCommit);

            Runnable postWriteRunnable = new Runnable() {
                    @Override
                    public void run() {
                        awaitCommit.run();
                        QueuedWork.removeFinisher(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);
        }

        // 有修改返回true
        private MemoryCommitResult commitToMemory() {
            long memoryStateGeneration;
            List<String> keysModified = null;
            Set<OnSharedPreferenceChangeListener> listeners = null;
            Map<String, Object> mapToWriteToDisk;

            synchronized (SharedPreferencesImpl.this.mLock) {
                // We optimistically don't make a deep copy until
                // a memory commit comes in when we're already
                // writing to disk.
                if (mDiskWritesInFlight > 0) {
                    // We can't modify our mMap as a currently
                    // in-flight write owns it.  Clone it before
                    // modifying it.
                    // noinspection unchecked
                    mMap = new HashMap<String, Object>(mMap);
                }
                mapToWriteToDisk = mMap;
                mDiskWritesInFlight++;
                
                // 监听器数量
                boolean hasListeners = mListeners.size() > 0;
                if (hasListeners) {
                    keysModified = new ArrayList<String>();
                    listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
                }

                synchronized (mEditorLock) {
                    boolean changesMade = false;
                    
                    // 如果调用了clear(),则mClear为true
                    if (mClear) {
                        // 需写入磁盘的数据不为空
                        if (!mapToWriteToDisk.isEmpty()) {
                            changesMade = true;
                            // 把需写入的数据全部置空
                            mapToWriteToDisk.clear();
                        }
                        mClear = false;
                    }

                    for (Map.Entry<String, Object> e : mModified.entrySet()) {
                        String k = e.getKey();
                        Object v = e.getValue();
                        // "this" is the magic value for a removal mutation. In addition,
                        // setting a value to "null" for a given key is specified to be
                        // equivalent to calling remove on that key.
                        if (v == this || v == null) {
                            if (!mapToWriteToDisk.containsKey(k)) {
                                continue;
                            }
                            mapToWriteToDisk.remove(k);
                        } else {
                            if (mapToWriteToDisk.containsKey(k)) {
                                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);
        }

        @Override
        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;
            } finally {
            }
            // 发送通知
            notifyListeners(mcr);
            // 返回写入磁盘的结果
            return mcr.writeToDiskResult;
        }

        private void notifyListeners(final MemoryCommitResult mcr) {
            // 没有需要通知的监听器或没有被修改的key,则直接退出
            if (mcr.listeners == null || mcr.keysModified == null ||
                mcr.keysModified.size() == 0) {
                return;
            }

            // 已在主线程,直接通知所有监听器
            if (Looper.myLooper() == Looper.getMainLooper()) {
                for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
                    // 逐个获取已修改的key
                    final String key = mcr.keysModified.get(i);
                    // 遍历所有监听器
                    for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
                        if (listener != null) {
                            // listener不为空,则发出通知
                            listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
                        }
                    }
                }
            } else {
                // 在主线程调用
                ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
            }
        }
    }

    /**
     * Enqueue an already-committed-to-memory result to be written
     * to disk.
     *
     * They will be written to disk one-at-a-time in the order
     * that they're enqueued.
     *
     * @param postWriteRunnable if non-null, we're being called
     *   from apply() and this is the runnable to run after
     *   the write proceeds.  if null (from a regular commit()),
     *   then we're allowed to do this disk write on the main
     *   thread (which in addition to reducing allocations and
     *   creating a background thread, this has the advantage that
     *   we catch them in userdebug StrictMode reports to convert
     *   them where possible to apply() ...)
     */
    // 从内存写入磁盘任务的排队队列,顺序是FIFO,依次执行
    // 如果参数postWriteRunnable非空,则执行apply()
    // 如果参数postWriteRunnable为空,则执行commit(),并允许数据在主线程写入磁盘
    // 这可以减少内存申请和避免创建后台线程,并能通过StrictMode报告去把commit()改为apply()
    private void enqueueDiskWrite(final MemoryCommitResult mcr,
                                  final Runnable postWriteRunnable) {
        // postWriteRunnable为空,同步提交数据到磁盘
        final boolean isFromSyncCommit = (postWriteRunnable == null);
        
        // 创建磁盘写入Runnable
        final Runnable writeToDiskRunnable = new Runnable() {
                @Override
                public void run() {
                    synchronized (mWritingToDiskLock) {
                        // 写入文件,是否同步写入isFromSyncCommit
                        writeToFile(mcr, isFromSyncCommit);
                    }
                    synchronized (mLock) {
                        mDiskWritesInFlight--;
                    }
                    // 仅apply()时执行
                    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;
            }
        }
        
        // 任务进队
        QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);
    }
    
    // 创建文件的输出流
    private static FileOutputStream createFileOutputStream(File file) {
        FileOutputStream str = null;
        try {
            // 创建文件输出流
            str = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            File parent = file.getParentFile();
            if (!parent.mkdir()) {
                Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
                return null;
            }
            FileUtils.setPermissions(
                parent.getPath(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                -1, -1);
            try {
                str = new FileOutputStream(file);
            } catch (FileNotFoundException e2) {
                Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
            }
        }
        return str;
    }
    
    // 写入文件
    @GuardedBy("mWritingToDiskLock")
    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;
        
        // 原文件是否存在
        boolean fileExists = mFile.exists();

        // 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 (!backupFileExists) {
                // 把当前文件改名为备份文件
                if (!mFile.renameTo(mBackupFile)) {
                    // 重命名文件失败
                    mcr.setDiskWriteResult(false, false);
                    return;
                }
            } else {
                // 备份文件已存在,删除源文件
                mFile.delete();
            }
        }

        // Attempt to write the file, delete the backup and return true as atomically as
        // possible.  If any exception occurs, delete the new file; next time we will restore
        // from the backup.
        try {
            // 创建写出流失败
            FileOutputStream str = createFileOutputStream(mFile);

            if (str == null) {
                mcr.setDiskWriteResult(false, false);
                return;
            }
            // 把内存中需要写入的数据按照Xml的格式写入到str
            XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);

            // 同步流
            FileUtils.sync(str);
            
            // 关闭文件写入
            str.close();
            
            // 修改文件权限
            ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);

            try {
                final StructStat stat = Os.stat(mFile.getPath());
                synchronized (mLock) {
                    mStatTimestamp = stat.st_mtim;
                    mStatSize = stat.st_size;
                }
            } catch (ErrnoException e) {
            }

            // 等待并删除备份的文件
            mBackupFile.delete();

            mDiskStateGeneration = mcr.memoryStateGeneration;

            mcr.setDiskWriteResult(true, true);

            mSyncTimes.add(Long.valueOf(fsyncDuration).intValue());
            mNumSync++;
            
            return;
        } catch (XmlPullParserException e) {
            Log.w(TAG, "writeToFile: Got exception:", e);
        } catch (IOException e) {
            Log.w(TAG, "writeToFile: Got exception:", e);
        }

        // 清除没用的已写入文件
        if (mFile.exists()) {
            if (!mFile.delete()) {
                Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
            }
        }
        mcr.setDiskWriteResult(false, false);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构与算法JavaScript描述

数据结构与算法JavaScript描述

[美] Michael McMillan / 王群锋、杜 欢 / 人民邮电出版社 / 2014-8 / 49.00元

通过本书的学习,读者将能自如地选择最合适的数据结构与算法,并在JavaScript开发中懂得权衡使用。此外,本书也概述了与数据结构与算法相关的JavaScript特性。 本书主要内容如下。 数组和列表:最常用的数据结构。 栈和队列:与列表类似但更复杂的数据结构。 链表:如何通过它们克服数组的不足。 字典:将数据以键-值对的形式存储。 散列:适用于快速查找和检索。......一起来看看 《数据结构与算法JavaScript描述》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具