SharedPreferences 的讲解以及项目中的使用


目录:

  • 简介
  • SharedPreferences使用步骤
  • 生成SharedPreferences的三种方式
  • 使用SharedPreferences注意事项
  • SharedPreferences注册监听
  • SharedPreferences的简单封装

简介:

SharedPreferences,是Android上一种轻量级数据储存方式。主要用于储存App配置信息;支持储存数据类型:boolean、int、float、long、String。


SharedPreferences使用步骤:

  1. 生成SharedPreferences对象;

  2. 生成editor对象;

  3. 由editor对SharedPreferences进行put、delete以及clear操作;

  4. commit()/apply()提交;


生成SharedPreferences的三种方式:

  1. PreferenceManager.getDefaultSharedPreferences(Context)生成:包名_preferences.xml;

  2. Activity.getPreferences(int mode)生成:Activity名.xml;

  3. Context.getSharedPreferences(String name,int mode)生成:name.xml

注:

  1. 生成的文件位置位于:data/data/包名/shared_prefs/目录下;
  2. mode一般为:MODE_PRIVATE;

使用SharedPreferences注意事项:

1. SharedPreferences文件应尽量小

SharedPreferences在创建的时候,会将整个文件加载到内存。如果文件过大,将会导致下列问题:

  1. 第一次从SharedPreferences中取值时,有可能阻碍主线程,使界面卡顿、掉帧;
  2. 解析SharedPreferences时会产生大量的临时对象,导致频繁GC,使界面卡顿;
  3. SharedPreferences中的key和value会一直存在内存中,占据大量内存;
2. 尽量少edit和apply提交
  1. 每次edit都会创建一个Editor对象,额外占据内存;
  2. 多次apply会造成界面的卡顿;
3. 不推荐使用SharedPreferences进行跨进

综上三点可以查看Android请不要滥用SharedPreference从源码上理解缘由。


SharedPreferences注册监听:

OnSharedPreferenceChangeListener是Android中SharedPreference文件发生变化的监听器。

当如下使用时:

@Override
protected void onCreate(Bundle savedInstanceState) {
  PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener(){
                @Override
                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                    Log.i("SP-->" ,"onSharedPreferenceChanged");
                }
            });
}

总是会出现回调方法无法回调的问题,其原因为:注册的监听器使用了匿名内部类。由于listener保持在WeakHashMap中,这就意味着不能监听一个匿名内部类,因为listener会成为垃圾收集的目标,只要离开目前的作用范围,它将会被作为垃圾收集,从WeakHashMap中删除并停止工作。源码实现:

final class SharedPreferencesImpl implements SharedPreferences {
......
  ......
    ......
  @GuardedBy("mLock")
  private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
            new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
......
  ......
    ......
  public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        synchronized(mLock) {
            mListeners.put(listener, CONTENT);
        }
    }
}

解决方案:
网上有很好的解决方案,可自行查阅,在这里不再贴代码,简单说一下解决思路:

  1. 将监听器listener作为成员变量;
  2. 在onResume()中注册监听;
  3. 在onPause()中注销监听;

也有在onStart()和onStop()中注册与注销的,不过笔者个人认为在onResume()和onPause()中进行注册和注销更有利于内存的使用,还望大家斟酌使用。


SharedPreferences的简单封装:

public class SharedPreferenceUtils {

    private static SharedPreferences sharedPreferences;
    private static SharedPreferences.Editor editor;

    /**
     * 使用PreferenceManager生成SharedPreferences
     * @param context   getApplicationContext();
     * @return          sharedpreferences
     */
    private SharedPreferences getSharedPreferences(Context context){
        return PreferenceManager.getDefaultSharedPreferences(context);
    }

    /**
     * 使用Activity生成SharedPreferences
     * @param activity   相关联的Activity
     * @param mode       文件模式
     * @return           SharedPreferences
     */
    private SharedPreferences getSharedPreferences(Activity activity,int mode){
        return activity.getPreferences(mode);
    }

    /**
     * 使用Context生成SharedPreferences
     * @param context   上下文
     * @param name      文件名
     * @param mode      文件模式
     * @return          SharedPreferences
     */
    private SharedPreferences getSharedPreferences(Context context,String name,int mode){
        return context.getSharedPreferences(name,mode);
    }

    private void put(HashMap<String,Object> data){
        editor = sharedPreferences.edit();
        Set<String> keys = data.keySet();
        for (String key : keys){
            Object value = data.get(key);
            parseValue(editor,key,value);
        }
        editor.apply();
    }

    private void put(String key, Object value) {
        editor = sharedPreferences.edit();
        parseValue(editor,key,value);
        editor.apply();
    }

    private Object getData(String key, Class<? extends Object> valueClass){

        if (valueClass.equals(Integer.class)){
            return sharedPreferences.getInt(key,0);
        }else if (valueClass.equals(String.class)){
            return sharedPreferences.getString(key,"null");
        }else if (valueClass.equals(Float.class)){
            return sharedPreferences.getFloat(key,0f);
        }else if (valueClass.equals(Boolean.class)){
            return sharedPreferences.getBoolean(key,false);
        }else if (valueClass.equals(Long.class)){
            return sharedPreferences.getLong(key,0L);
        }
        return null;
    }

    private void clear(){
        sharedPreferences.edit().clear().apply();
    }

    private void deleteData(String key){
        sharedPreferences.edit().remove(key).apply();
    }

    private void deleteData(String[] keys){
        editor = sharedPreferences.edit();
        for (String key : keys){
            editor.remove(key);
        }
        editor.apply();
    }

    private void parseValue(SharedPreferences.Editor editor,String key,Object value){
        Class<? extends Object> valueClass;
        valueClass = value.getClass();
        if (valueClass.equals(Integer.class)){
            editor.putInt(key,(int)value);
        }else if (valueClass.equals(String.class)){
            editor.putString(key,(String)value);
        }else if (valueClass.equals(Float.class)){
            editor.putFloat(key,(float)value);
        }else if (valueClass.equals(Boolean.class)){
            editor.putBoolean(key,(boolean)value);
        }else if (valueClass.equals(Long.class)){
            editor.putLong(key,(long)value);
        }
    }

    public static class Builder{

        private WeakReference<SharedPreferenceUtils> weakSPUtils;
        private SharedPreferenceUtils spUtils;

        public Builder(Context context){
            isSPUtilsEnpty();
            sharedPreferences = spUtils.getSharedPreferences(context);
        }

        public Builder(Activity activity,int mode){
            isSPUtilsEnpty();
            sharedPreferences = spUtils.getSharedPreferences(activity,mode);
        }

        public Builder(Context context,String name,int mode){
            isSPUtilsEnpty();
            sharedPreferences = spUtils.getSharedPreferences(context,name,mode);
        }

        public Builder putData(HashMap<String,Object> data){
            spUtils.put(data);
            return this;
        }

        public Builder putData(String key,Object value){
            spUtils.put(key,value);
            return this;
        }

        public Builder deleteData(String[] keys){
            spUtils.deleteData(keys);
            return this;
        }

        public Builder deleteData(String key){
            spUtils.deleteData(key);
            return this;
        }

        public Builder clear(){
            spUtils.clear();
            return this;
        }

        public Object getData(String key,Class<? extends Object> valueClass){
            return spUtils.getData(key,valueClass);
        }

        public Builder create(){
            return this;
        }

        private void isSPUtilsEnpty() {
            if (weakSPUtils.get() == null){
                weakSPUtils = new WeakReference<SharedPreferenceUtils>(new SharedPreferenceUtils());
                spUtils = weakSPUtils.get();
            }
        }

    }
}

封装支持的功能:

  1. 单个和批量添加:putData(HashMap data)、putData(key,value);
  2. 单个和批量删除:deleteData(keys)、deleteData(key);
  3. 获取数据:getData(key,valueClass);
  4. 清理数据:clear();

简单使用:
案例:批量添加数据

HashMap<String,Object> data = new HashMap<>();
   data.put("int",1);
   data.put("float",2.123f);
   data.put("String","abc");

SharedPreferenceUtils.Builder builder = new SharedPreferenceUtils.Builder(getApplicationContext())
                .putData(data)
                .create();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,085评论 25 707
  • 360修炼第27天:我们常常说的三大过滤网指的是删减、扭曲、一般化。每个人都有独一无二的储存和提取信息的过滤网,不...
    天外飞仙_85e0阅读 253评论 0 0
  • 就在刚刚前一秒,我还在想标题要写什么,手底下就不自觉的出来这几个字 你要记得每时每刻都要美丽,记得涂口红,记得打腮...
    学霸与学渣的美好爱情阅读 205评论 0 1
  • 提到父亲,就忽然间想起了之前看到的一个笑话,说是一对父母带着自己的小孩参加朋友的婚礼,席间有人逗小朋友,说你爸妈结...
    沐梓芢卿阅读 239评论 0 0
  • “我就是恨你,我恨你抢先实现了我的理想,我恨你优越的生活,我恨当初如此不屑的你如今有了光明的前途,我恨我自己还没来...
    活着1111阅读 158评论 0 0