前言

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文件中读取字节流然后转化为对象。

存储对象流程:

  1. 对象必须实现 Serializable 序列化,不能使用 Parcelable 序列化,因为 out.writeObject 无法写入 Parcelable 序列化的对象
  2. 将序列化的对象转为字节流
  3. 通过将字对象进行用Base64转码,写入sp中
  4. 通过key读取到编码后的字节流,并进行Base64解码
  5. 将解码后的 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 集合。

更多相关文章

  1. 类和 Json对象
  2. Android(安卓)下使用 JSON 实现 HTTP 请求
  3. 十二、Android(安卓)UI开发专题
  4. 初遇Android——跨进程使用Service
  5. 《Android面试宝典》学习笔记(第三章:组件)
  6. 【Android】 保存图片到系统图库, 并立即显示在图库中
  7. Android中对Handle机制的理解
  8. Android(安卓)双开沙箱 VirtualApp 源码分析(一)
  9. Android(安卓)webview与js交换JSON对象数据示例

随机推荐

  1. Android常用功能代码块
  2. android中实现全局变量
  3. Android(安卓)KeyListener
  4. Android(安卓)adb shell后面可用的常用命
  5. Android优秀开源项目大全
  6. Android优秀开源框架集
  7. json defines classes that conflict wit
  8. Android知识搜罗
  9. Android从SD卡中加载图片或读取信息
  10. table 标签使用