写作原因:SharedPreferences作为Android常用的数据存储手段(常常被用来存储用户设置),其重要性无需多言,最近做项目对很多工具进行封装,将SharedPreferences做一个知识总结,方便自己日后使用,也帮助Android新手学习使用。
定义
先来看看Android官方API对于SharedPreferences(以下简称SP)的定义:SP是通过getSharedPreferences(String,int)返回的用于访问和储存设置(Preferences,我本人理解为设置)数据的接口。对于许多特定的设置的数据集,存在一个单例的类能够将数据集给所有客户分享。修改设置数据必须通过SharedPreferences.Editor对象来确保设置的值保持一个一致的状态并且当它们提交时能受控制。SP对象通过get()方法必须在Application中保持一成不变。简单来说,SharedPreferences是一种轻型的数据存储方式,基于XML文件存储key-value键值对(只能存储简单的类型)数据,常用来存储一些简单的配置信息。
基本使用
下面是使用SharedPreferences的基本步骤:
1. 获得SharedPreferences对象;
2. 获得SharedPreferences.Editor对象;
3. 通过Editor接口的putXxx方法保存key-value对其中Xxx表示不同的数据类型;
4. 通过Editor接口的commit方法保存key-value对。
(注意:上述API定义已经说得很清楚了,SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象来实现的,所以SP对象不能直接用于写入数据)
具体代码如下:
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(Context context); //获取系统默认的SharedPreferences对象(Context中传入上下文,如MainActivity.this); //或者:SharedPreferences pref = getSharedPreferences("XML文件名",“读取权限如MODE_PRIVATE"); Editor editor = pref.edit();//获得Editor对象; editor.putString(key,value);//保存key-value对(有多种类型如putInt等); editor.remove(key);//删除键值对; editor.commit();//一定要提交; pref.getString(key,defValue);//用于取值,key对应要取出的值的key,defValue是没取到值时的默认值;
上面是基本的SP的使用方法,封装是面向对象的精华,鸿洋大神已经帮我们把SP封装好了,先膜拜一下,然后我们一起来学习内部实现:
废话不多说,直接上代码
package com.mhpro.mhlife.utils; import android.content.Context; import android.content.SharedPreferences; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; /** * Created by JackHuang on 2016/9/14. */ public class MHSingleData { /** * 保存在手机里面的名字 */ public static final String FILE_NAME = "shared_data"; /** * 保存数据的方法,拿到数据保存数据的基本类型,然后根据类型调用不同的保存方法 * * @param key * @param object */ public static void setObject(Context context,String key, Object object) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { editor.putInt(key, (Integer) object); } else if (object instanceof Boolean) { editor.putBoolean(key, (Boolean) object); } else if (object instanceof Float) { editor.putFloat(key, (Float) object); } else if (object instanceof Long) { editor.putLong(key, (Long) object); } else { editor.putString(key, object.toString()); } SharedPreferencesCompat.apply(editor); } /** * 获取保存数据的方法,我们根据默认值的到保存的数据的具体类型,然后调用相对于的方法获取值 * * @param key 键的值 * @param defaultObject 默认值 * @return */ public static Object getObjectForKey(Context context,String key, Object defaultObject) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { return sharedPreferences.getInt(key, (Integer) defaultObject); } else if (defaultObject instanceof Boolean) { return sharedPreferences.getBoolean(key, (Boolean) defaultObject); } else if (defaultObject instanceof Float) { return sharedPreferences.getFloat(key, (Float) defaultObject); } else if (defaultObject instanceof Long) { return sharedPreferences.getLong(key, (Long) defaultObject); } else { return sharedPreferences.getString(key, null); } } /** * 移除某个key值已经对应的值 * * @param key */ public static void remove(Context context,String key) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.remove(key); SharedPreferencesCompat.apply(editor); } /** * 清除所有的数据 */ public static void clear(Context context) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.clear(); SharedPreferencesCompat.apply(editor); } /** * 查询某个key是否存在 * * @param key * @return */ public static boolean contains(Context context,String key) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); return sharedPreferences.contains(key); } /** * 返回所有的键值对 * * @return */ public static Map<String, ?> getAll(Context context) { SharedPreferences sharedPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); return sharedPreferences.getAll(); } /** * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 * * @author zhy * */ private static class SharedPreferencesCompat { private static final Method sApplyMethod = findApplyMethod(); /** * 反射查找apply的方法 * * @return */ @SuppressWarnings({ "unchecked", "rawtypes" }) private static Method findApplyMethod() { try { Class clz = SharedPreferences.Editor.class; return clz.getMethod("apply"); } catch (NoSuchMethodException e) { } return null; } /** * 如果找到则使用apply执行,否则使用commit * * @param editor */ public static void apply(SharedPreferences.Editor editor) { try { if (sApplyMethod != null) { sApplyMethod.invoke(editor); return; } } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } editor.commit(); } } }
上面类将对SP的操作封装成了静态方法put(),get(),remove(),clear()等,put(),remove(),get(),clear()等,其实现基于上述基本步骤,只是根据形参中的object的数据类型选择不同的写入方法。另外有一点不同,上面类中使用的不是commit方法而是apply方法,为什么?找一下他的博客,发现:commit方法是同步的,并且我们很多时候的commit操作都是UI线程中,毕竟是IO操作,尽可能异步;所以我们使用apply进行替代,apply异步的进行写入。这样就清楚了。上述类通过反射获取SP.Editor中的apply()方法,重命名为sApplyMethod,调用invoke方法来实现将数据传递给editor,然后editor提交,从而完成apply()封装。
本次关于SharedPreferences即封装类SPUtils的解析就到这,如有错误希望能够指正。