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);
    }
}

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

查看所有标签

猜你喜欢:

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

Algorithms + Data Structures = Programs

Algorithms + Data Structures = Programs

Niklaus Wirth / Prentice Hall / 1975-11-11 / GBP 84.95

It might seem completely dated with all its examples written in the now outmoded Pascal programming language (well, unless you are one of those Delphi zealot trying to resist to the Java/.NET dominanc......一起来看看 《Algorithms + Data Structures = Programs》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具