当前位置:   article > 正文

面试:SharedPreference原理及多进程_sharepreference是不是进程安全的

sharepreference是不是进程安全的

1、SharePreferences是线程安全的 里面的方法有大量的synchronized来保障。

2、SharePreferences不是进程安全的即使你用了MODE_MULTI_PROCESS 。

3、第一次getSharePreference会读取磁盘文件,异步读取,写入到内存中,后续的getSharePreference都是从内存中拿了,所有的get都是从内存中读取。

4、第一次读取完毕之前 所有的get/set请求都会被卡住等待读取完毕后再执行,所以第一次读取会有ANR风险。

5、提交都是写入到内存和磁盘中 。apply跟commit的区别在于

commit:内存同步 只不过要等待磁盘写入结束才返回 直接返回写入成功状态 true or false

apply:是内存同步 然后磁盘异步写入任务放到一个单线程队列中 等待调用,方法无返回 即void

6、 所以单个文件千万不要太大 否则会严重影响性能。

1、SharePreference多进程的问题

Andorid 7.0及以上会抛出异常,Sharepreferences不再支持多进程模式。多进程共享文件会出现问题的本质在于,因为不同进程,所以线程同步会失效。要解决这个问题,可尝试跨进程解决方案,如ContentProvider、AIDL、Service。腾讯微信团队的MMKV采用内存映射的方式,解决SharedPreferences的各种问题。

2、SharedPreference的加载的主要过程:

1、找到对应name的文件
2、加载对应文件到内存中SharedPreference
3、一个xml文件对应一个SharedPreferences单例

3、apply和commit

1、commit()方法和apply()方法的区别:

commit()方法是同步的有返回结果,同步保证使用Countdownlatch,即使同步但不保证往磁盘的写入是发生在当前线程的。

apply()方法是异步的具体发生在QueuedWork中,里面维护了一个单线程去执行磁盘写入操作。

2、commit()和apply()方法其实都是Block主线程。commit()只要在主线程调用就会堵塞主线程;apply()方法磁盘写入操作虽然是异步的,但是当组件(Activity Service BroadCastReceiver)这些系统组件特定状态转换的时候,会把QueuedWork中未完成的那些磁盘写入操作放在主线程执行,且如果比较耗时会产生ANR,手动可怕。

3、跨进程操作,需要借助Android平台常规的IPC手段(如,AIDL ContentProvider等)来完成。

4、SharePreferences运行机制

首先,我们看下SharePreferences的简单使用,代码如下:

  1. mSharedPreferences = context.getSharedPreferences("test", Context.MODE_PRIVATE);
  2. SharedPreferences.Editor editor = mSharedPreferences.edit();
  3. editor.putString(key, value);
  4. editor.apply();

context.getSharedPreferences其实就是简单的调用ContextImpl的getSharedPreferences,具体实现如下

  1. @Override
  2. public SharedPreferences getSharedPreferences(String name, int mode) {
  3. SharedPreferencesImpl sp;
  4. synchronized (ContextImpl.class) {
  5. if (sSharedPrefs == null) {
  6. sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
  7. }
  8. final String packageName = getPackageName();
  9. ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
  10. if (packagePrefs == null) {
  11. packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();
  12. sSharedPrefs.put(packageName, packagePrefs);
  13. }
  14. sp = packagePrefs.get(name);
  15. if (sp == null) {
  16. <!--读取文件-->
  17. File prefsFile = getSharedPrefsFile(name);
  18. sp = new SharedPreferencesImpl(prefsFile, mode);
  19. <!--缓存sp对象-->
  20. packagePrefs.put(name, sp);
  21. return sp;
  22. }
  23. }
  24. <!--跨进程同步问题-->
  25. if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
  26. getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
  27. sp.startReloadIfChangedUnexpectedly();
  28. }
  29. return sp;
  30. }

这里面数据的加载的地方需要看下,比如,SharePreferences数据的加载是同步还是异步?数据加载是new SharedPreferencesImpl对象时候开始的

  1. SharedPreferencesImpl(File file, int mode) {
  2. mFile = file;
  3. mBackupFile = makeBackupFile(file);
  4. mMode = mode;
  5. mLoaded = false;
  6. mMap = null;
  7. startLoadFromDisk();
  8. }

startLoadFromDisk很简单,新开一个子线程,然后去通过 XmlUtils.readMapXml() 方法把指定的 SharedPreferences 文件的所有的键值对都读出来,然后存放到一个 map 中。如果其他线程想要在读取之前就是用的话,就会被阻塞,一直wait等待,直到数据读取完成。

  1. private void startLoadFromDisk() {
  2. synchronized (mLock) {
  3. mLoaded = false;
  4. }
  5. new Thread("SharedPreferencesImpl-load") {
  6. public void run() {
  7. loadFromDiskLocked();
  8. }
  9. }.start();
  10. }
  11. private void loadFromDiskLocked() {
  12. ...
  13. Map map = null;
  14. StructStat stat = null;
  15. try {
  16. stat = Os.stat(mFile.getPath());
  17. if (mFile.canRead()) {
  18. BufferedInputStream str = null;
  19. try {
  20. <!--读取xml中配置-->
  21. str = new BufferedInputStream(
  22. new FileInputStream(mFile), 16*1024);
  23. map = XmlUtils.readMapXml(str);
  24. }...
  25. mLoaded = true;
  26. ...
  27. <!--唤起其他等待线程-->
  28. notifyAll();
  29. }

可以看到其实就是直接使用xml解析工具XmlUtils,直接在当前线程读取xml文件,所以,如果xml文件稍大,尽量不要在主线程读取,读取完成之后,xml中的配置项都会被加载到内存,再次访问的时候,其实访问的是内存缓存。

每日一问:谈谈 SharedPreferences 的 apply() 和 commit() - 南尘 - 博客园

每日一问:谈谈 SharedPreferences 的 apply() 和 commit()_linshijun33的博客-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码优化者/article/detail/60782
推荐阅读
相关标签
  

闽ICP备14008679号