继续沿用提出问题,然后通过寻找源码的方式来探究结果。
问题1.SharedPreferences为什么是线程安全但不是进程安全的?
SharedPreferences数据的读写是线程安全的,但不是进程安全的。单个进程的多个线程是运行在一个内存地址空间里面,多个进程分别运行在不同的内存地址空间。那么两个进程的子线程都不在一个内存地址空间,锁那些自然就限制不了,所以多个进程同时读写一个SharedPreferences可能会出现数据不一致,所以是进程不安全。
问题2:SharedPreferences在获取时的name,mode有什么作用?
name:SharedPreferences使用了一个ArrayMap来管理name与file的映射,通过name来获取对应储存数据的file。
问题2.1那么为什么要使用ArrayMap?
主要原因是ArrayMap更省内存,一般的使用场景下Android官方也更推荐用ArrayMap替代HashMap,这篇文章有详细的讲解https://www.jianshu.com/p/9663c2f77a9c,然后再以这个文件为key取出SharedPreferences映射的文件。
mode:没啥好说的,就一个private完事儿
问题3:SharedPreferences底层是用什么进行的数据存储?
使用的是xml文件
问题3.1:SharedPreferences为什么使用xml做数据存储而不用json呢?
主要是因为时代的限制。SharedPreferences可以说是伴随Android的存在就存在的东西。Android刚出的时代xml还是数据存储的主流,等到json流行后,想再将xml替换为json就要涉及到各种已有项目的兼容性问题,大家都知道覆盖安装SharedPreferences这些数据还会保留的。虽然xml解析相对复杂,体积更大。但比json仍有更好的一面,比如扩展性、对数据的描述性上,所以这可能也是官方觉得没必要替换的原因吧(所以有了官方建议SharedPreferences别存大量数据)
问题4:SharedPreferences数据存储位置?
一般是在data/data/<包名>/shared_prefs目录下。可能还会存在某个文件级加密相关的目录,DE,CE这些,是由设备制造商选择是否启用,与我们无关。
问题5:SharedPreferences数据存储过程是什么样的?
先使用editor,内部维护了一个HashMap(这里为什么又用HashMap了?说好的推荐ArrayMap呢,原来操作较大数据HashMap效率更高)用来持有待持久化(也就是需要存入xml文件)的数据。
问题5.1:为什么要先在内存里持有一份呢?
因为IO操作比较吃资源,先内存放一份,等到要提交的时候再一起IO到xml文件里
问题5.2:调用apply和commit都可以持久化到本地。这两个方法有什么区别吗?
commit:同步操作,也就是说执行完IO操作后才执行后续代码。我们知道IO是需要时间的,那么在写入这段时间内,又进行了修改就会导致数据不一致了。所以数据再提交到内存的时候SharedPreference会把原map拷贝一份,避免在写入数据过程中发生修改。
问题5.2.1:什么是浅拷贝、深拷贝?
浅拷贝一个对象是指对对象内的基本数据类型将值拷贝,引用类型将引用拷贝过去。深拷贝一个对象,是把这个待拷贝对象完全新建了一个对象,里面的属性引用类型的话也是新建的引用,只是把值那些都复制过去了,所以深拷贝需要自己重写,要告知程序怎么进行拷贝
接问题5.2然后将待写入的数据提交至内存,至此,这个editor的数据就固定了,然后进行写入磁盘。
问题5.2.2:由谁写入磁盘呢?
写入磁盘会创建一个消息交由handler进行处理,创建了一个持有子线程的looper的handler,进行写入,虽然消息是异步的,但会一直等待消息的执行结果
没等待到结果锁就不会释放,主线程来时就阻塞住了,这就是SharedPreferences会造成anr的原因
接问题5.2 apply:异步操作,并不是说可以多个线程同时进行写入,而是不必等待写入完毕才执行后续代码。可以这么理解,apply就相当于是为每一个commit都创建一个子线程。
问题6:SharedPreferences数据怎么取出的?
获取SharedPreferences时会将对应的文件加载进内存(异步加载的),将文件解析成HashMap。
问题6.1:如果文件还没加载完毕就取值会怎么样呢?
会阻塞住线程,一直等待加载文件完毕才返回值。
接问题6后续的值都从这个map里取。
问题6.2:如果对SharedPreferences进行了修改,会重新加载一次文件?
不会,见问题5数据持久化过程,数据在提交到内存的时候就会把待修改的数据同步修改到这个map里。
问题7.SharedPreferences的使用权限?
在Android系统里维护了一个ArrayMap<packageName,ArrayMap<File, SharedPreferencesImpl>>的map,所以一个应用只能使用自己包名下的SharedPreferences。
问题7.1:那相同包名,不同签名的应用,能获取到对方的SharedPreferences吗?
相同包名,不同签名的两个apk并不能同时存在。
问题7.1.1:那么双开的应用呢?
详见应用双开实现原理,所以也不会共用到一个SharedPreferences
网友评论