美文网首页Android潜修者Android 开发经验集Android面试
Android面试一天一题(14 Day:SharedPrefe

Android面试一天一题(14 Day:SharedPrefe

作者: goeasyway | 来源:发表于2016-06-21 20:42 被阅读4156次

    如果说程序可以简单理解成“指令和数据的集合”,那么你在任何平台上编程都难以离开数据存储,在Android平台上自然也不会例外。说到数据的存储,对于Key-Value对应的数据存取,Android提供SharedPreferences的方式可以进行方便的操作。大家也都觉得它的使用很简单,但是有时候简单的地方也会发生问题,而且你很难查觉到问题根源在这个地方。

    面试题:修改SharedPreferences后两种提交方式有什么区别?

    SharedPreferences类是一个接口类,真正的实现类是SharedPreferencesImpl。修改SharedPreferences需要获取它的Editor,在对Editor进行put操作后,最后通过commit或者apply提交修改到内存和文件。当然有了两种都可以提交的方法,肯定要区别一下的。从实现类SharedPreferencesImpl的源码上看也很容易看出两者的区别:

    commit这种方式很常用,在比较早的SDK版本中就有了,这种提交修改的方式是同步的,会阻塞调用它的线程,并且这个方法会返回boolean值告知保存是否成功(如果不成功,可以做一些补救措施)。
    而apply是异步的提交方式,目前Android Studio也会提示大家使用这种方式。

    还有一点用得比较少的,就是SharedPreferences还提供一个监听接口可以监听SharedPreferences的键值变化,需要监控键值变化的可以用registerOnSharedPreferenceChangeListener添加监听器。

    public interface SharedPreferences {
        /**
         * Interface definition for a callback to be invoked when a shared
         * preference is changed.
         */
        public interface OnSharedPreferenceChangeListener {
            void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
        }
    

    多进程操作和读取SharedPreferences的问题

    前段时间,项目组里发现一个偶现的问题,从Http明明获取了正确的数据保存到SharedPreferences,但立即再从SharedPreferences读取这个值时发现是初始值。开始大家一直把精力放在Http的请求上,最后才发现是SharedPreferences多进程间数据共享会导致的问题。

    在SDK 3.0及以上版本,可以通过Context.MODE_MULTI_PROCESS属性来实现SharedPreferences多进程共享。如下设置:

        public static SharedPreferences getSharedPreferences(String name) {
            if (null != context) {
                if (Build.VERSION.SDK_INT >= 11) {
                    return context.getSharedPreferences(name, Context.MODE_MULTI_PROCESS);
                } else {
                    return context.getSharedPreferences(name, Context.MODE_PRIVATE);
                }
            }
    
            return null;
        }
    

    本来以为通过MODE_MULTI_PROCESS属性使用SharedPreferences就可以实现不同时程间共享数据,但是在真正使用中确发现有会有一定概率出现这个取值出错(变为初始值)问题。

    最后发现在官网上Google也在SDK 6.0的版本将这个MODE_MULTI_PROCESS标识为deprecated(不赞成使用)。目前来说,越来越多的项目在不断的膨胀,为了降低单个进程的内存占用率,使用"android:process"配置一些组件在单独的进程中运行已经是司空见惯了,所以大家在遇到自己的项目有多进程时,要注意一下SharedPreferences的问题。

    小结

    在一个进程中,SharedPreference往往建单个实例就可以了,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。

    因为SharedPreferences在多进程方面的问题,大家也可以思考下能不能自己实现一个加强版的SharedPreferences解决这些问题,网上也有一些开源的替代方案,如Github上的tray。(建议大家先想一下,再看这个项目。)

    相关文章

      网友评论

      • 8cd249b8ddf2:所以多进程间共享数据,还是用数据库比较好吧?如果是需要频繁读写的。
        7794dde0494b:我看MODE_MULTI_PROCESS的注释上说的多进程之间推荐使用ContentProvider
      • 6ee72519b51d:以前也想过 同时访问的问题 但是没细想
      • one_cup:同二楼,您的每篇文章都有看,并尝试从自己角度区思考解决方案,关于并发访问SharedPreferences出现的问题,感觉如果是多线程的的话可能也会出现相同的问题吧?出现问题的根源是数据写进去了不能够共享还是说数据没有写进去就已经被读出来了?感觉把自己绕进去了,明天去查一下资料
        one_cup:@one_cup 最近看之前看过的书,其中在开发艺术探索中看到作者对shredpreference多进程访问的说明,豁然明朗,之所以会再写入之后仍会获得到没写入之前的数据是因为,系统在对shredpreference的读写有一定的缓存策略,也就是说在内存中会有一份shredpreference文件的缓存,因此会丢失数据。
        one_cup:@签到钱就到 你的意思是在shredpreference读取的时候其实Xml中已经写入更新的参数了,但是读取的却是之前的数据是吗?这种情况是在多线程中也会出现吗?突然想到之前在开发艺术探索书中好像有相关的介绍。感觉自己学的好乱啊!这几天GreenDAO Glide搞得人都快疯掉了。
        签到钱就到:@one_cup xml文件里是后来更新的参数,但是用shredpreference读取的时候读出来的是更新之前的,也就是获取到的是之前的一个缓存。更新后的参数可以用直接读xml数据,再自己解析的笨方式获取到。
      • wudouxingjun:写的很不错
      • timloong:还真是不知道多进程怎么搞,多谢~
      • 一亩水塘:有道理!!!
      • d1bf7f4f4fc4:赞一个,每次上简书都看你更新没,一直在关注你的这个系列。写的非常好,加油↖(^ω^)↗
        goeasyway:@sawder :stuck_out_tongue_winking_eye:

      本文标题:Android面试一天一题(14 Day:SharedPrefe

      本文链接:https://www.haomeiwen.com/subject/dxwldttx.html