Android(安卓)-- SharedPreferences保存基本数据、序列化对象、List数据
前言
Android提供了五种数据存储方式:
- 使用 SharedPreferences 存储数据
- 文件存储数据
- SQLite 数据库存储方式
- 使用 ContentProvider 存储数据
- 网络存储数据
在 Android 下做持久化的数据存储,大部分是用 sqlite 数据库或 sharepreference。为了少写 sql 语句,大部分都是用 ORM 形式的开源数据库框架,例如 greendao 和 cupboard 或者 dao4,但在一般小型存储系统中,还是用 sharepreference 存储比较方便。
1 SharedPreferences 存储
1.1 SharedPreferences 可存储的数据类型
SharedPreferences 是 Android 平台上一个轻量级的存储辅助类,用来保存应用的一些常用配置。
SharedPreferences 可存储的数据类型有:
- 四种基本类型数据(int,float,long,boolean)+ String
- List类型的数据:List< String>,List< JavaBean>
- 序列化对象
- Map
集合
最终数据是以xml形式进行存储。
SharedPreferences 文件都是存放在 /data/data//shared_prefs/目录下的,在模拟器上可以看见该文件;在真机上,需要对真机root后,才能看到该文件。
1.2 SharedPreferences 权限
- MODE_PRIVATE:默认操作模式,和直接传0效果相同,表示只有当前应用程序才可以对这个 SharedPreferences 文件进行读写。
- MODE_WORLD_READABLE:指定此 SharedPreferences 对其他程序只读且无法修改。
- MODE_WORLD_WRITEABLE:指定此 SharedPreferences 能被其他程序读写。
- MODE_MULTI_PROCESS:Android2.3之后已经弃之不用了。
下面总结 SharedPreferences 可存储的数据类型。
1.3 存储四种基本类型数据
SharedPreferences 可存储四种基本类型数据(int,float,long,boolean)+ String。
SPUtil
/** * 获取SharedPreference保存的value * 值的类型:(int,float,long,boolean)+String * * @param context 上下文 * @param key 储存值的key * @param clazz 获取值的类型 int,float,long,boolean)+String * @param T * @return 值 */ public static T getValue(Context context, String key, Class clazz) { if (context == null) { throw new RuntimeException("context is null"); } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); return getValue(key, getT(clazz), sp); } /** * 获取SharedPreference保存的value * 值的类型:(int,float,long,boolean)+String * * @param key 储存值的key * @param T 获取值的类型 int,float,long,boolean)+String * @param sp SharedPreferences * @param T * @return 值 */ private static T getValue(String key, T t, SharedPreferences sp) { if (t == null) { return null; } if (t instanceof Integer) { return (T) Integer.valueOf(sp.getInt(key, 0)); } else if (t instanceof String) { return (T) sp.getString(key, ""); } else if (t instanceof Boolean) { return (T) Boolean.valueOf(sp.getBoolean(key, false)); } else if (t instanceof Long) { return (T) Long.valueOf(sp.getLong(key, 0L)); } else if (t instanceof Float) { return (T) Float.valueOf(sp.getFloat(key, 0L)); } Log.e(TAG, "无法找到" + key + "对应的值"); return null; } /** * 通过反射创建类实例 * 反射有两种方式创建类实例: * 1、Class.newInstance():只能调用无参的构造函数(默认构造函数) * 2、Constructor.newInstance():可以根据传入的参数,调用任意构造构造函数。 * Integer、Boolean、Long、Float 没有默认构造函数,只能通过 Constructor.newInstance() 调用 * String 是有默认构造函数的,两种方法都适用 * @param clazz String.class、Integer.class、Boolean.class、Long.class、Float.class * @param T * @return T */ private static T getT(Class clazz) { T t = null; String clazzName = clazz.getName(); Log.e(TAG, "基本类型名字是[" + clazzName + "]"); try { if ("java.lang.Integer".equals(clazzName)) { t = clazz.getConstructor(int.class).newInstance(1); } else if ("java.lang.String".equals(clazzName)) { t = clazz.newInstance(); } else if ("java.lang.Boolean".equals(clazzName)) { t = clazz.getConstructor(boolean.class).newInstance(false); } else if ("java.lang.Long".equals(clazzName)) { t = clazz.getConstructor(long.class).newInstance(0L); } else if ("java.lang.Float".equals(clazzName)) { t = clazz.getConstructor(float.class).newInstance(0F); } } catch (InstantiationException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (IllegalAccessException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (InvocationTargetException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (NoSuchMethodException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } return t; } /** * 使用SharedPreference保存value * * @param context 上下文 * @param key 储存值的key * @param value 值 */ public static void setValue(Context context, String key, Object value) { if (context == null) { throw new RuntimeException("context is null"); } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); setValue(key, value, sp); } /** * 使用SharedPreference保存value * * @param key 储存值的key * @param value 值 * @param sp SharedPreferences */ private static void setValue(String key, Object value, SharedPreferences sp) { SharedPreferences.Editor editor = sp.edit(); if (value instanceof Integer) { editor.putInt(key, (Integer) value); } else if (value instanceof String) { editor.putString(key, (String) value); } else if (value instanceof Boolean) { editor.putBoolean(key, (Boolean) value); } else if (value instanceof Long) { editor.putLong(key, (Long) value); } else if (value instanceof Float) { editor.putFloat(key, (Float) value); } editor.commit(); }
注:
通过反射创建类实例
反射有两种方式创建类实例:
1、Class.newInstance():只能调用无参的构造函数(默认构造函数)
2、Constructor.newInstance():可以根据传入的参数,调用任意构造构造函数
Integer、Boolean、Long、Float 没有默认构造函数,只能通过 Constructor.newInstance() 调用
String 是有默认构造函数的,两种方法都适用
在 SPTestActivity 中使用
//存储 String str = etContent.getText().toString().trim(); if (TextUtils.isEmpty(str)) { ToastUtils.toast(this, "请输入内容"); return; }// SPUtil.setValue(this, "base_value", str);// SPUtil.setValue(this, "base_value_int", 2);// SPUtil.setValue(this, "base_value_boolean", true);// SPUtil.setValue(this, "base_value_long", 3L); SPUtil.setValue(this, "base_value_float", 3.5F); ToastUtils.toast(this, "数据保存成功!"); //读取 String value = SPUtil.getValue(this, "base_value", String.class);// int value = SPUtil.getValue(this, "base_value_int", Integer.class);// boolean value = SPUtil.getValue(this, "base_value_boolean", Boolean.class);// long value = SPUtil.getValue(this, "base_value_long", Long.class); float value = SPUtil.getValue(this, "base_value_float", Float.class); ToastUtils.toast(this, String.valueOf(value));
1.4 存储序列化对象
SharedPreferences 存储对象是将对象转化为字节流,然后写入本地xml文件中; 读取时,从xml文件中读取字节流然后转化为对象。
存储对象流程:
- 对象必须实现 Serializable 序列化,不能使用 Parcelable 序列化,因为 out.writeObject 无法写入 Parcelable 序列化的对象
- 将序列化的对象转为字节流
- 通过将字对象进行用Base64转码,写入sp中
- 通过key读取到编码后的字节流,并进行Base64解码
- 将解码后的 String 反序列化,返回对象
SPUtil
/** * 使用SharedPreference保存序列化对象 * 用Base64.encode将字节文件转换成Base64编码保存在String中 * * @param context 上下文 * @param key 储存对象的key * @param object object对象 对象必须实现Serializable序列化,否则会出问题, * out.writeObject 无法写入 Parcelable 序列化的对象 */ public static void setObject(Context context, String key, Object object) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); //创建字节输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //创建字节对象输出流 ObjectOutputStream out = null; try { //然后通过将字对象进行64转码,写入sp中 out = new ObjectOutputStream(baos); out.writeObject(object); String objectValue = new String(Base64.encode(baos.toByteArray(), Base64.DEFAULT)); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, objectValue); editor.commit(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (baos != null) { baos.close(); } if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * 获取SharedPreference保存的对象 * 使用Base64解密String,返回Object对象 * * @param context 上下文 * @param key 储存对象的key * @param 泛型 * @return 返回保存的对象 */ public static T getObject(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); if (sp.contains(key)) { String objectValue = sp.getString(key, null); byte[] buffer = Base64.decode(objectValue, Base64.DEFAULT); //一样通过读取字节流,创建字节流输入流,写入对象并作强制转换 ByteArrayInputStream bais = new ByteArrayInputStream(buffer); ObjectInputStream ois = null; try { ois = new ObjectInputStream(bais); T t = (T) ois.readObject(); return t; } catch (StreamCorruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (bais != null) { bais.close(); } if (ois != null) { ois.close(); } } catch (IOException e) { e.printStackTrace(); } } } return null; }
在 SPTestActivity 中使用
//存储UserModel userModel = new UserModel();userModel.name = "张三";userModel.age = 20;SPUtil.setObject(this, "user_model", userModel);ToastUtils.toast(this, "数据保存成功!");//读取UserModel user = SPUtil.getObject(this, "user_model");ToastUtils.toast(this, "姓名:" + user.name + ",年龄:" + user.age);
UserModel 对象
public class UserModel implements Serializable { public int id; public String name; public int age;}
1.5 存储List类型的数据
用于保存List数据,支持的类型有:
- List< String>
- List< JavaBean>
存储List类型的数据
/** * 使用SharedPreferences保存List * 支持类型:List,List * * @param context 上下文 * @param key 储存的key * @param dataList 存储数据 * @param 泛型 */ public static void setDataList(Context context, String key, List dataList) { if (null == dataList || dataList.size() < 0) { return; } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Gson gson = new Gson(); //转换成json数据,再保存 String strJson = gson.toJson(dataList); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, strJson); editor.commit(); }
读取List类型的数据
/** * 获取SharedPreferences保存的List * * @param context 上下文 * @param key 储存的key * @param 泛型 * @return 存储List数据 */ public static List getDataList(Context context, String key, Class cls) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); List dataList = new ArrayList(); String strJson = sp.getString(key, null); if (null == strJson) { return dataList; } Gson gson = new Gson(); //使用泛型解析数据会出错,返回的数据类型是LinkedTreeMap dataList = gson.fromJson(strJson, new TypeToken>() { }.getType()); return dataList; }
在 SPTestActivity 中使用
//存储List userList = new ArrayList<>();for (int i = 0; i < 5; i ++) { UserModel userModel1 = new UserModel(); userModel1.name = "名字:" + i; userList.add(userModel1);}SPUtil.setDataList(this, "user_list", userList);ToastUtils.toast(this, "数据保存成功!");//读取List dataList = SPUtil.getDataList(this, "user_list");StringBuffer buffer = new StringBuffer(); for (UserModel user1 : dataList) { buffer.append(user1.name + ";"); } ToastUtils.toast(this, buffer.toString());
运行后,会发现,在读取数据的时候,会抛出异常:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.rs.recyclerviewdemo.model.UserModel
看错误信息,是 “类型” 转换问题。
断点调试下
用这种方式读取数据:
/** * 获取SharedPreferences保存的List * * @param context 上下文 * @param key 储存的key * @param 泛型 * @return 存储List数据 */ public static List getDataList(Context context, String key, Class cls) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); List dataList = new ArrayList(); String strJson = sp.getString(key, null); if (null == strJson) { return dataList; } Gson gson = new Gson(); //使用泛型解析数据会出错,返回的数据类型是LinkedTreeMap dataList = gson.fromJson(strJson, new TypeToken>() { }.getType()); return dataList; }
断点调试结果:
可看到,返回的类型是个LinkedTreeMap,所以当把解析后的集合遍历复制给 UserModel 的时候就会报 “类型” 转换错误的异常。
对从 SharedPreferences 读取数据那块代码进行改造:
public static List getDataList(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); List dataList = new ArrayList(); String strJson = sp.getString(key, null); if (null == strJson) { return dataList; } Gson gson = new Gson(); //使用泛型解析数据会出错,返回的数据类型是LinkedTreeMap// dataList = gson.fromJson(strJson, new TypeToken>() {// }.getType()); //这样写,太死 dataList = gson.fromJson(strJson, new TypeToken>() { }.getType()); return dataList; }
在解析时,将 T 泛型改为 UserModel 对象进行解析,再次运行,读取正常。
断点调试查看数据:
dataList 里存入的是 UserModel 对象,解析正常。
但是解析类型规定死,这样太死了,无法扩展。
再次进行改造:
/** * 获取SharedPreferences保存的List * * @param context 上下文 * @param key 储存的key * @param 泛型 * @return 存储List数据 */ public static List getDataList(Context context, String key, Class cls) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); List dataList = new ArrayList(); String strJson = sp.getString(key, null); if (null == strJson) { return dataList; } Gson gson = new Gson(); //使用泛型解析数据会出错,返回的数据类型是LinkedTreeMap// dataList = gson.fromJson(strJson, new TypeToken>() {// }.getType()); //这样写,太死// dataList = gson.fromJson(strJson, new TypeToken>() {// }.getType()); JsonArray arry = new JsonParser().parse(strJson).getAsJsonArray(); for (JsonElement jsonElement : arry) { dataList.add(gson.fromJson(jsonElement, cls)); } return dataList; }
调用:
List dataList = SPUtil.getDataList(this, "user_list", UserModel.class);StringBuffer buffer = new StringBuffer();for (UserModel user1 : dataList) { buffer.append(user1.name + ";");}ToastUtils.toast(this, buffer.toString());
OK ! ! !
或者参考LinkedTreeMap的处理方法
1.6 存储 Map 集合
SharedPreferences 存储 Map
/** * 使用SharedPreferences保存集合 * @param context 上下文 * @param key 储存的key * @param map map数据 */ public static void setHashMapData(Context context, String key, Map map){ if (map == null) { return ; } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Gson gson = new Gson(); String strJson = gson.toJson(map); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, strJson); editor.commit(); } /** * 获取SharedPreferences保存的集合 * @param context 上下文 * @param key 储存的key * @param clsV 解析类型 * @return Map集合 */ public static Map getHashMapData(Context context, String key, Class clsV){ SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Map map = new HashMap<>(); String strJson = sp.getString(key, ""); Gson gson = new Gson(); JsonObject obj =new JsonParser().parse(strJson).getAsJsonObject(); Set> entrySet = obj.entrySet(); for (Map.Entry entry : entrySet) { String entryKey = entry.getKey(); JsonObject value = (JsonObject) entry.getValue(); map.put(entryKey, gson.fromJson(value, clsV)); } return map; }
使用:
//存储Map map = new HashMap<>();for (int i = 0; i < 5; i++) { UserModel userModel1 = new UserModel(); userModel1.name = "姓名:" + i; map.put(i +"", userModel1);}SPUtil.setHashMapData(this, "user_map", map);ToastUtils.toast(this, "数据保存成功!");//读取Map userMap = SPUtil.getHashMapData(this, "user_map", UserModel.class);UserModel userModel1 = userMap.get("1");ToastUtils.toast(this, userModel1.name);
2 SharedPreferences 工具类封装
SPUtil
package com.example.rs.recyclerviewdemo.util;import android.content.Context;import android.content.SharedPreferences;import android.util.Base64;import android.util.Log;import com.google.gson.Gson;import com.google.gson.JsonArray;import com.google.gson.JsonElement;import com.google.gson.JsonObject;import com.google.gson.JsonParser;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.StreamCorruptedException;import java.lang.reflect.InvocationTargetException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Set;/** * Created by sgll on 2019/1/15. * SharedPreferences工具类 * 保存的数据类型有: * 1、四种基本类型数据(int,float,long,boolean)+ String * 2、List类型的数据 * 3、存储序列化对象 * 4、存储Map集合 */public class SPUtil { private static String SP_NAME = "recyclerviewdemo_sp"; private static String TAG = "SharedPreferenceUtil"; /** * 获取SharedPreference保存的value * 值的类型:(int,float,long,boolean)+String * * @param context 上下文 * @param key 储存值的key * @param clazz 获取值的类型 int,float,long,boolean)+String * @param T * @return 值 */ public static T getValue(Context context, String key, Class clazz) { if (context == null) { throw new RuntimeException("context is null"); } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); return getValue(key, getT(clazz), sp); } /** * 获取SharedPreference保存的value * 值的类型:(int,float,long,boolean)+String * * @param key 储存值的key * @param T 获取值的类型 int,float,long,boolean)+String * @param sp SharedPreferences * @param T * @return 值 */ private static T getValue(String key, T t, SharedPreferences sp) { if (t == null) { return null; } if (t instanceof Integer) { return (T) Integer.valueOf(sp.getInt(key, 0)); } else if (t instanceof String) { return (T) sp.getString(key, ""); } else if (t instanceof Boolean) { return (T) Boolean.valueOf(sp.getBoolean(key, false)); } else if (t instanceof Long) { return (T) Long.valueOf(sp.getLong(key, 0L)); } else if (t instanceof Float) { return (T) Float.valueOf(sp.getFloat(key, 0L)); } Log.e(TAG, "无法找到" + key + "对应的值"); return null; } /** * 通过反射创建类实例 * 反射有两种方式创建类实例: * 1、Class.newInstance():只能调用无参的构造函数(默认构造函数) * 2、Constructor.newInstance():可以根据传入的参数,调用任意构造构造函数。 * Integer、Boolean、Long、Float 没有默认构造函数,只能通过 Constructor.newInstance() 调用 * String 是有默认构造函数的,两种方法都适用 * @param clazz String.class、Integer.class、Boolean.class、Long.class、Float.class * @param T * @return T */ private static T getT(Class clazz) { T t = null; String clazzName = clazz.getName(); Log.e(TAG, "基本类型名字是[" + clazzName + "]"); try { if ("java.lang.Integer".equals(clazzName)) { t = clazz.getConstructor(int.class).newInstance(1); } else if ("java.lang.String".equals(clazzName)) { t = clazz.newInstance(); } else if ("java.lang.Boolean".equals(clazzName)) { t = clazz.getConstructor(boolean.class).newInstance(false); } else if ("java.lang.Long".equals(clazzName)) { t = clazz.getConstructor(long.class).newInstance(0L); } else if ("java.lang.Float".equals(clazzName)) { t = clazz.getConstructor(float.class).newInstance(0F); } } catch (InstantiationException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (IllegalAccessException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (InvocationTargetException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } catch (NoSuchMethodException e) { Log.e(TAG, "类型输入错误或者复杂类型无法解析[" + e.getMessage() + "]"); e.printStackTrace(); } return t; } /** * 使用SharedPreference保存value * * @param context 上下文 * @param key 储存值的key * @param value 值 */ public static void setValue(Context context, String key, Object value) { if (context == null) { throw new RuntimeException("context is null"); } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); setValue(key, value, sp); } /** * 使用SharedPreference保存value * * @param key 储存值的key * @param value 值 * @param sp SharedPreferences */ private static void setValue(String key, Object value, SharedPreferences sp) { SharedPreferences.Editor editor = sp.edit(); if (value instanceof Integer) { editor.putInt(key, (Integer) value); } else if (value instanceof String) { editor.putString(key, (String) value); } else if (value instanceof Boolean) { editor.putBoolean(key, (Boolean) value); } else if (value instanceof Long) { editor.putLong(key, (Long) value); } else if (value instanceof Float) { editor.putFloat(key, (Float) value); } editor.commit(); } /** * 使用SharedPreference保存序列化对象 * 用Base64.encode将字节文件转换成Base64编码保存在String中 * * @param context 上下文 * @param key 储存对象的key * @param object object对象 对象必须实现Serializable序列化,否则会出问题, * out.writeObject 无法写入 Parcelable 序列化的对象 */ public static void setObject(Context context, String key, Object object) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); //创建字节输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //创建字节对象输出流 ObjectOutputStream out = null; try { //然后通过将字对象进行64转码,写入sp中 out = new ObjectOutputStream(baos); out.writeObject(object); String objectValue = new String(Base64.encode(baos.toByteArray(), Base64.DEFAULT)); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, objectValue); editor.commit(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (baos != null) { baos.close(); } if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * 获取SharedPreference保存的对象 * 使用Base64解密String,返回Object对象 * * @param context 上下文 * @param key 储存对象的key * @param 泛型 * @return 返回保存的对象 */ public static T getObject(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); if (sp.contains(key)) { String objectValue = sp.getString(key, null); byte[] buffer = Base64.decode(objectValue, Base64.DEFAULT); //一样通过读取字节流,创建字节流输入流,写入对象并作强制转换 ByteArrayInputStream bais = new ByteArrayInputStream(buffer); ObjectInputStream ois = null; try { ois = new ObjectInputStream(bais); T t = (T) ois.readObject(); return t; } catch (StreamCorruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (bais != null) { bais.close(); } if (ois != null) { ois.close(); } } catch (IOException e) { e.printStackTrace(); } } } return null; } /** * 使用SharedPreferences保存List * 支持类型:List,List * * @param context 上下文 * @param key 储存的key * @param dataList 存储数据 * @param 泛型 */ public static void setDataList(Context context, String key, List dataList) { if (null == dataList || dataList.size() < 0) { return; } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Gson gson = new Gson(); //转换成json数据,再保存 String strJson = gson.toJson(dataList); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, strJson); editor.commit(); } /** * 获取SharedPreferences保存的List * * @param context 上下文 * @param key 储存的key * @param 泛型 * @return 存储List数据 */ public static List getDataList(Context context, String key, Class cls) { SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); List dataList = new ArrayList(); String strJson = sp.getString(key, null); if (null == strJson) { return dataList; } Gson gson = new Gson(); //使用泛型解析数据会出错,返回的数据类型是LinkedTreeMap// dataList = gson.fromJson(strJson, new TypeToken>() {// }.getType()); //这样写,太死// dataList = gson.fromJson(strJson, new TypeToken>() {// }.getType()); JsonArray arry = new JsonParser().parse(strJson).getAsJsonArray(); for (JsonElement jsonElement : arry) { dataList.add(gson.fromJson(jsonElement, cls)); } return dataList; } /** * 使用SharedPreferences保存集合 * @param context 上下文 * @param key 储存的key * @param map map数据 */ public static void setHashMapData(Context context, String key, Map map){ if (map == null) { return ; } SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Gson gson = new Gson(); String strJson = gson.toJson(map); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, strJson); editor.commit(); } /** * 获取SharedPreferences保存的集合 * @param context 上下文 * @param key 储存的key * @param clsV 解析类型 * @return Map集合 */ public static Map getHashMapData(Context context, String key, Class clsV){ SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); Map map = new HashMap<>(); String strJson = sp.getString(key, ""); Gson gson = new Gson(); JsonObject obj =new JsonParser().parse(strJson).getAsJsonObject(); Set> entrySet = obj.entrySet(); for (Map.Entry entry : entrySet) { String entryKey = entry.getKey(); JsonObject value = (JsonObject) entry.getValue(); map.put(entryKey, gson.fromJson(value, clsV)); } return map; }}
使用
package com.example.rs.recyclerviewdemo.activity;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.text.TextUtils;import android.view.View;import android.widget.EditText;import com.example.rs.recyclerviewdemo.R;import com.example.rs.recyclerviewdemo.model.UserModel;import com.example.rs.recyclerviewdemo.util.SPUtil;import com.example.rs.recyclerviewdemo.util.ToastUtils;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import butterknife.BindView;import butterknife.ButterKnife;import butterknife.OnClick;/** * Created by sgll on 2019/1/15. */public class SPTestActivity extends AppCompatActivity { @BindView(R.id.et_content) EditText etContent; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sp_test); ButterKnife.bind(this); } @OnClick({R.id.bt_set_base, R.id.bt_get_base, R.id.bt_set_object, R.id.bt_get_object, R.id.bt_set_list, R.id.bt_get_list, R.id.bt_set_map, R.id.bt_get_map}) void onClick(View view){ int viewId = view.getId(); switch (viewId) { case R.id.bt_set_base: String str = etContent.getText().toString().trim(); if (TextUtils.isEmpty(str)) { ToastUtils.toast(this, "请输入内容"); return; }// SPUtil.setValue(this, "base_value", str);// SPUtil.setValue(this, "base_value_int", 2);// SPUtil.setValue(this, "base_value_boolean", true);// SPUtil.setValue(this, "base_value_long", 3L); SPUtil.setValue(this, "base_value_float", 3.5F); ToastUtils.toast(this, "数据保存成功!"); break; case R.id.bt_get_base:// String value = SPUtil.getValue(this, "base_value", String.class);// int value = SPUtil.getValue(this, "base_value_int", Integer.class);// boolean value = SPUtil.getValue(this, "base_value_boolean", Boolean.class);// long value = SPUtil.getValue(this, "base_value_long", Long.class); float value = SPUtil.getValue(this, "base_value_float", Float.class); ToastUtils.toast(this, String.valueOf(value)); break; case R.id.bt_set_object: UserModel userModel = new UserModel(); userModel.name = "张三"; userModel.age = 20; SPUtil.setObject(this, "user_model", userModel); ToastUtils.toast(this, "数据保存成功!"); break; case R.id.bt_get_object: UserModel user = SPUtil.getObject(this, "user_model"); ToastUtils.toast(this, "姓名:" + user.name + ",年龄:" + user.age); break; case R.id.bt_set_list: List userList = new ArrayList<>(); for (int i = 0; i < 5; i ++) { UserModel userModel1 = new UserModel(); userModel1.name = "名字:" + i; userList.add(userModel1); }// List userList = new ArrayList<>();// for (int i = 0; i < 5; i ++) {// userList.add("你好:" + i);// }// List userList = new ArrayList<>();// for (int i = 0; i < 5; i ++) {// userList.add(i);// } SPUtil.setDataList(this, "user_list", userList); ToastUtils.toast(this, "数据保存成功!"); break; case R.id.bt_get_list: List dataList = SPUtil.getDataList(this, "user_list", UserModel.class); StringBuffer buffer = new StringBuffer(); for (UserModel user1 : dataList) { buffer.append(user1.name + ";"); }// List dataList = SPUtil.getDataList(this, "user_list", String.class);// for (String stra : dataList) {// buffer.append(stra + ";");// }// List dataList = SPUtil.getDataList(this, "user_list", Integer.class);// for (Integer stra : dataList) {// buffer.append(stra + ";");// } ToastUtils.toast(this, buffer.toString()); break; case R.id.bt_set_map: Map map = new HashMap<>(); for (int i = 0; i < 5; i++) { UserModel userModel1 = new UserModel(); userModel1.name = "姓名:" + i; map.put(i +"", userModel1); } SPUtil.setHashMapData(this, "user_map", map); ToastUtils.toast(this, "数据保存成功!"); break; case R.id.bt_get_map: Map userMap = SPUtil.getHashMapData(this, "user_map", UserModel.class); UserModel userModel1 = userMap.get("1"); ToastUtils.toast(this, userModel1.name); break; default: break; } }}
xml
<?xml version="1.0" encoding="utf-8"?>
布局图:
UserModel
package com.example.rs.recyclerviewdemo.model;import java.io.Serializable;/** * Created by sgll on 2019/1/16. */public class UserModel implements Serializable { public int id; public String name; public int age;}
3 总结
SharedPreference s是无法直接保存 Object,List 集合和 Map 集合的,需要先将它们转换为字符串,再保存到 SharedPreferences 中,取的时候再把对应的字符串转为 Object,List 集合或者 Map 集合。
更多相关文章
- 类和 Json对象
- Android(安卓)下使用 JSON 实现 HTTP 请求
- 十二、Android(安卓)UI开发专题
- 初遇Android——跨进程使用Service
- 《Android面试宝典》学习笔记(第三章:组件)
- 【Android】 保存图片到系统图库, 并立即显示在图库中
- Android中对Handle机制的理解
- Android(安卓)双开沙箱 VirtualApp 源码分析(一)
- Android(安卓)webview与js交换JSON对象数据示例