程序员人生 网站导航

一个高大上的SharedPreferences工具类——XPrefs

栏目:综合技术时间:2016-07-07 13:52:39

背景

SharedPreferences经常使用来存储1些轻量级的数据,SharedPreferences存储的就是1个key-value(键值对)。Sharedpreferences在平常的android开发中使用的应当算是挺频繁的,通常我们开发者为了存储1个key,都会在1个类里写好对应的getter和setter方法,而且还要手动写key,也就是说写了方法还要定义key。项目写的多了以后明显会感觉到这样写很麻烦。这时候候XPrefs就出现了,并很好的解决了这个问题。

XPrefs可以直接保存和读取实例对象,是SharedPreferences中的ORM,还可以通过接口来做文章,这类方式用起来是最方便的,具体介绍接着往下看。

用法

初始化

XPrefs.bind(this);

初始化是绑定了contenxt,以后的操作就不需要传入context参数了,如果你传入activity,会自动转成application context,这样就避免了内存泄漏的问题,固然你也能够在application的类里进行绑定操作。

整存整取

/** * 整存整取,把javabean类中的所有有效的字段都写入sharedpreferences中 */ private void saveAll() { //如果想切换写入的sharedpreferences文件,可以调用 // XPrefs.changeFileName("your custom sp file's name"); //如果设置Mode,如果调用了changeFileName方法,则必须在changeFileName以后调用 // XPrefs.changeFileMode(Context.MODE_PRIVATE); //或直接调用 // XPrefs.changeFileNameAndMode("your custom sp file's name", Context.MODE_PRIVATE); XPrefs.changeFileName(spFile1); UserBean userBean = new UserBean(); userBean.setAge(21); userBean.setFuns(1000); userBean.setMoney(100); userBean.setName("韩梅梅"); userBean.setVIP(true); XPrefs.saveAll(userBean); //读取,查看存入的数据 userBean = XPrefs.get(UserBean.class); LogUtils.i("saveAll " + userBean); }

上面代码中的changeFileName和changeFileMode方法分别是设置Sharedpreferences文件的name和mode的,要注意的是,如果调用了changeFileName,那末需要调用changeFileMode的话就必须要在changeFileName以后调用。如果不设置name,默许操作的文件名是XPrefs,默许的mode是Context.MODE_PRIVATE。

接着new了1个UserBean的实例,给需要保存的属性设置了对应的值,然后调用saveAll就把UserBean中所有的属性都保存进了SharedPreferences文件里,其中key是属性名,value是属性的值。让我们接着看看UserBean这个类,

/** * final 修饰的字段不会被存储 */ private final String InvalidField="InvalidField"; /** * 添加了XIgnore注解的字段会被忽视,也不会被存储 */ @XIgnore private String IgnoreField="IgnoreField"; //目前支持以下几种类型的数据存储 private String name; private float money; private int age; private boolean isVIP; private long funs; ...省略1些getter、setter方法和toString()...

用final修饰的属性和加上@XIgnore注解的属性都是被疏忽的,不会被存储的。存储的时候,key是属性名(如”name”,”money”,”age”…),value是属性的值。最后通过下面这行代码读取所有存入的数据,直接调用userbean的getter方法,就能够使用这些数据。
userBean = XPrefs.get(UserBean.class);
整存整取的好处除方便之外,就是效力高,不管存储了多少属性,都只操作了1次文件,有点类似于数据库中的事物。

既然可以保存和读取全部javaBean,那末也应当可以对javaBean中的单个属性进行存储和读取。

单个字段的存储和读取

/** * 单个字段的存储和读取 */ public void save() { //修改存储的sharedpreferences文件,mode默许为Context.MODE_PRIVATE XPrefs.changeFileName(spFile2); UserBean userBean = new UserBean(); userBean.setAge(42); userBean.setFuns(2000); userBean.setMoney(200); userBean.setName("李雷"); userBean.setVIP(false); XPrefs.save(userBean, "name"); XPrefs.save(userBean, "age"); XPrefs.save(userBean, "funs"); XPrefs.save(userBean, "money"); XPrefs.save(userBean, "isVIP"); //读取,查看存入的数据 Class cls = UserBean.class; boolean isVIP = XPrefs.getBoolean(cls, "isVIP"); String name = XPrefs.getString(cls, "name"); int age = XPrefs.getInt(cls, "age"); long funs = XPrefs.getLong(cls, "funs"); float money = XPrefs.getFloat(cls, "money"); LogUtils.i("save name=" + name + ";money=" + money + ";age=" + age + ";funs=" + funs + ";isVIP=" + isVIP); //整取 userBean = XPrefs.get(UserBean.class); LogUtils.i("save " + userBean.toString()); }

上面的代码演示了对UserBean中的字段单独进行读写操作。

XPrefs.save(userBean, "name"); String name = XPrefs.getString(cls, "name");

要注意的save和getString方法传入的第2个参数得和属性名相同,才能到达想要的效果。也就是如果定义了1个属性private String name;那末传入的就得是“name”。看上去有点麻烦,确切挺麻烦的,但这只是1种用法,更方便的用法后面会介绍。

使用接口和注解

private void saveAllAndFollowYourHeart() { IUser user = XPrefs.getObject(IUser.class); user.setName("Tom"); user.setAge(18); user.setFuns(4000); user.setMoney(40000); user.setVip(true); LogUtils.i("IUser name=" + user.getName() + ";money=" + user.getMoney() + ";age=" + user.getAge()+ ";funs=" + user.getFuns() + ";isVIP=" + user.getVip()); }

首先,调用了XPrefs.getObject(IUser.class)拿到了接口IUser的1个实例对象user,接着分别调用了user的set和get方法,看上去没甚么,但是,在履行set方法的时候就已把数据 存了起来,履行get方法就是把数据读取出来。
具体让我们看看IUser接口,

@XSPFile(fileName = "IUser", fileMode = Context.MODE_PRIVATE) public interface IUser { @XSet(key = "name", fileName = "IUser", fileMode = Context.MODE_PRIVATE) void setName(String name); @XGet(key = "name") String getName(); @XSet(key = "age") void setAge(int age); @XGet(key = "age") int getAge(); @XSet(key = "funs") void setFuns(int funs); @XGet(key = "funs") int getFuns(); @XSet(key = "vip") void setVip(boolean vip); @XGet(key = "vip") boolean getVip(); @XSet(key = "money") void setMoney(float money); @XGet(key = "money") float getMoney(); }

有3个注解XSPFile,XSet和XGet,这3个注解都不是必须的。其中XSPFile是用来指定file name和mode的,用来标记接口,作用域是类。

@XSPFile(fileName = "IUser", fileMode = Context.MODE_PRIVATE)

XSet和XGet则是来标记方法的作用的,1个方法用XSet标记了,那末这个方法的作用就是写入数据到指定的SharedPreferences文件中的,其中key就是写入时的key。XSet也能指定写入的文件 name和mode,如果XSPFile和XSet同时指定了文件的name和mode,那末以XSet指定的为准。

@XSet(key = "name", fileName = "IUser", fileMode = Context.MODE_PRIVATE) void setName(String name);

如果1个方法用XGet标记了,那末这个方法的作用就是从SharedPreferences文件中读取数据,XGet中的key就是读取时的key,其他的和XSet1样。

@XGet(key = "name") String getName();

这样也不是很好,每写1个方法就得加1个注解,好麻烦的说,所以还可以更简单点。

使用接口不用注解

private void saveAllAndFollowYourHeartToo() { IEmployee employee = XPrefs.getObject(IEmployee.class); employee.setName("员工"); employee.setAge(22); employee.setSalary(3000); LogUtils.i("IEmployee name=" + employee.getName() + ";age=" + employee.getAge() + ";salary=" + employee.getSalary()); }

这里的用法和用注解的是1样的,主要还是IEmployee接口上的区分,

@XSPFile(fileName = "IEmployee", fileMode = Context.MODE_PRIVATE) public interface IEmployee { /** * 存储字段 name * * @param name value */ void setName(String name); /** * 读取字段 name * * @return */ String getName(); void setAge(int age); int getAge(); void setSalary(float salary); float getSalary(); }

可以看到,不用注解以后,代码少了将近1半。
这个时候key主要是通过解析方法名来得到的,所以1个方法以set开头的方法的作用就是写入数据到指定的SharedPreferences文件中,其中key就是方法名除去set的后半部份,且首字母小写,举个例子,方法setName的key就是name;
那末1个以get开头的方法的作用也是很明显了,就是从SharedPreferences文件中读取数据,其中key就是方法名出去get的后半部份,首字母也是小写,举个例子,方法getName的key就是name。看上去已很方便了,但是这都不算甚么,更骚的在后面。

最后1种用法

private void saveAllAndFollowYourHeartThree() { IStudent student = XPrefs.getObject(IStudent.class); student.name("学生3号"); student.score(100); student.sex("女"); LogUtils.i("IStudent name=" + student.name() + ";score=" + student.score() + ";sex=" + student.sex()); }

这里的用法和上面两种仍然没有甚么区分,主要的区分还是在IStudent接口上,

@XSPFile(fileName = "IStudent") public interface IStudent { /** * 存储字段 name * * @param name value */ void name(String name); /** * 读取字段 name * * @return */ String name(); void score(int score); int score(); void sex(String sex); String sex(); }

和上种用法相比,区分就是方法名中没有了set和get,那末这是怎样判断方法的作用和要存入数据的key的呢?首先,key就是方法名,完完全全的懒人的写法;其次,方法的作用是通过方法参数和方法返回值来判断的,

  1. 如果1个方法有1个参数,那末这个方法的作用就是写入数据到指定的SharedPreferences文件中,key是方法名,值是传入的参数;
  2. 如果1个方法没有参数并且方法的返回值不是void,那末这个方法的作用就是从指定的SharedPreferences文件中读取数据,key是方法名。

这几种通过接口来做文章的写法,XPrefs内部是通过动态代理来做的,java对动态代理的支持仅限于接口,所以用的是接口,如果不用接口的话就得引入第3方的库,这类我也做过,但是项目的体积就会变得更大,终究我放弃了。

混淆注意事项

  • 不要混淆XPrefs中的注解类型,添加混淆配置:
-keep class * extends java.lang.annotation.Annotation { *; }
  • 对用于持久化的实体类不要混淆,包括javaBean和接口,在demo中是这样的:
-keep interface com.huxq17.xprefs.example.interfaces.** { *; } -keepclasseswithmembers class com.huxq17.xprefs.example.UserBean { <fields>; <methods>; }

具体根据自己项目情况而定。

最后

XPrefs的地址:点击我,这次这个项目的灵感来源于github上的1个项目,当时我就在思考怎样做出1个简单易用的SharedPreferences工具类,为了寻觅灵感我就在github上面乱逛,1次偶然的机会我看到了这个项目,浏览了项目里的代码,思路立马就清晰了,项目地址:androidInject,非常感谢这个项目的作者。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐