SharedPreferences的分析(一)

正气清白,流于乾坤

SharedPreferences是Android开发中经常使用的一种轻量级存储方式。本着『知其然知其所以然』的宗旨,我们来探讨一下SharedPreferences的实现过程。

1. 基本知识

  1. SharedPreferences是以Key-Value(键值对)的形式进行存储的;
  2. SharedPreferences最终存储在xml文件上;
  3. SharedPreferences是线程安全的,但不是进程安全的(MODE_MULTI_PROCESS是个鸡肋。)

2. 基本框架

SharedPreferences是一个接口,其内部有包含除了用于获取数据的方法外,还有

  1. 用于存储,删除和提交数据Editor接口
  2. 用于监听的SharedPreferences变化的OnSharedPreferenceChangeListener接口
public interface SharedPerferences{

     public interface OnSharedPreferenceChangeListener {
        /**
         * Called when a shared preference is changed, added, or removed. 
         * (当SharedPreferences更新,添加,删除时被调用)
         * This callback will be run on your main thread.(此回调运行在主线程)
         */
        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
    }
    public interface Editor{
    	// 存储操作
        Editor putXXX(String key, XXX value);
        // 删除操作
        Editor remove(String key);
        
        Editor clear();
        // 用于提交的commit()和 apply()方法
        boolean commit();
        
        void apply();
    }
    ···
    Map<String, ?> getAll();
    // 获取数据
    XXX getXXX(String key, XXX defValue);
   
    boolean contains(String key);
    // 返回给我们一个Editor,用于执行其存储,更新和提交操作。
    Editor edit();
}

通过上面的代码我们可以看到SharePerferences和Editor都是接口,主要的核心实现逻辑都在其实现类中。


final class SharedPreferencesImpl implements SharedPreferences {
	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;

	 @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
    public Editor edit() {
        synchronized (mLock) {
            awaitLoadedLocked();
        }
        return new EditorImpl();
    }

	  public final class EditorImpl implements Editor {
	  
        private final Object mEditorLock = new Object();
        
		// 通过putXXX()方法,可以看出值都是先保存在mModified里面
        @GuardedBy("mEditorLock")
        private final Map<String, Object> mModified = new HashMap<>();

		 @Override
        public Editor putString(String key, @Nullable String value) {
            synchronized (mEditorLock) {
                mModified.put(key, value);
                return this;
            }
        }
		
		 @Override
        public Editor remove(String key) {
            synchronized (mEditorLock) {
                mModified.put(key, this);
                return this;
            }
        }
		 @Override
		 public void apply() {
		 	// 大体流程跟commit()一样,后文讲解
		 }
		 
		 @Override
		 public boolean commit() {
		 	// 注意这个commitToMemory()方法。以及MemoryCommitResult类
		   final MemoryCommitResult mcr = commitToMemory();
		    
		   	SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
			
			notifyListeners(mcr);
			
            return mcr.writeToDiskResult;
		}
	}
	// 内部类MemoryCommitResult
	private static class MemoryCommitResult {
        @Nullable final Set<OnSharedPreferenceChangeListener> listeners;
        // 注意这个Map
        final Map<String, Object> mapToWriteToDisk;
        // 这里的CountDownLatch保证线程的执行顺序。
        final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);

        @GuardedBy("mWritingToDiskLock")
        volatile boolean writeToDiskResult = false;
        boolean wasWritten = false;

        void setDiskWriteResult(boolean wasWritten, boolean result) {
            this.wasWritten = wasWritten;
            writeToDiskResult = result;
            writtenToDiskLatch.countDown();
        }
    }
	
}

通过查看源码,我们会发现数据基本都在三个HashMap中进行流转,如下图所示:

在这里插入图片描述

3. 基本操作

  1. 获取数据getXXX():

    从SharedPreferencesImpl的mMap中获取数据;

  2. 存储数据putXXX():
    1. 首先我们需要通过edit()获取EditorImpl对象;
    2. 通过putXXX()方法将数据存入到EditorImplmModified变量中。
  3. 提交操作commit()或apply():
    1. 通过commitToMemory()方法将数据同步SharedPreferencesImpl的mMap中,然后将EditorImpl中的mModified的数据转移到MemoryCommitResultmapToWriteToDisk变量中。
    2. 调用enqueueDiskWrite()方法,将MemoryCommitResultmapToWriteToDisk写入到XML文件中。

4. 总结

这里将SharedPreferences的整体流程给梳理出来,下一篇文章将深入到源码的细节去进一步分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值