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。看上去已很方便了,但是这都不算甚么,更骚的在后面。
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就是方法名,完完全全的懒人的写法;其次,方法的作用是通过方法参数和方法返回值来判断的,
这几种通过接口来做文章的写法,XPrefs内部是通过动态代理来做的,java对动态代理的支持仅限于接口,所以用的是接口,如果不用接口的话就得引入第3方的库,这类我也做过,但是项目的体积就会变得更大,终究我放弃了。
-keep class * extends java.lang.annotation.Annotation { *; }
-keep interface com.huxq17.xprefs.example.interfaces.** { *; }
-keepclasseswithmembers class com.huxq17.xprefs.example.UserBean {
<fields>;
<methods>;
}
具体根据自己项目情况而定。
XPrefs的地址:点击我,这次这个项目的灵感来源于github上的1个项目,当时我就在思考怎样做出1个简单易用的SharedPreferences工具类,为了寻觅灵感我就在github上面乱逛,1次偶然的机会我看到了这个项目,浏览了项目里的代码,思路立马就清晰了,项目地址:androidInject,非常感谢这个项目的作者。