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,非常感謝這個項目的作者。