Android AutoValue使用和扩展库
一、什么是autovalue
意思就是自动值,谷歌出品,添加@autovalue
这样的注解 就能够自动生成代码,使得程序可能更短,更清晰。 支持java1.6+
github:
首先看一个bean类,user.java:
public class user{ private string name; private string addr; private int age; private string gender; private string hobby; private string sign; public string getname() { return name; } public void setname(string name) { this.name = name; } ....(太多就省略了) }
一堆的getter和setter代码很多,到时候添加tostring
、hashcode
、equals
这些代码就更麻烦了(虽然ide有快速生成),这时候autovalue就来拯救世界了。
二、基本使用
一步一脚印
2.1 导包
初次使用需要注意,官方只说了在module依赖,这样会build失败的,对于新手来说会一脸懵逼,因为需要apt。
项目的build.gradle添加依赖:
dependencies { //添加这行 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }
在module的build.gradle依赖以下,当前最新是1.4.1
//顶部添加 apply plugin: 'com.neenbedankt.android-apt' dependencies { compile "com.google.auto.value:auto-value:1.4.1" apt "com.google.auto.value:auto-value:1.4.1" }
重新sync即可
2.2 使用autovalue标识bean
现在来重新编写user类:
@autovalue public abstract class user { abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); }
然后build -> make module一下,这时候就会生成autovalue_user.java
,在build\generated\source\apt\debug\包名\autovalue_user.java
里面的代码为:
final class autovalue_user extends user { private final string name; private final string addr; private final int age; private final string gender; private final string hobby; private final string sign; autovalue_user( string name, string addr, int age, string gender, string hobby, string sign) { if (name == null) { throw new nullpointerexception("null name"); } this.name = name; if (addr == null) { throw new nullpointerexception("null addr"); } this.addr = addr; this.age = age; if (gender == null) { throw new nullpointerexception("null gender"); } this.gender = gender; if (hobby == null) { throw new nullpointerexception("null hobby"); } this.hobby = hobby; if (sign == null) { throw new nullpointerexception("null sign"); } this.sign = sign; } @override string name() { return name; } @override string addr() { return addr; } @override int age() { return age; } @override string gender() { return gender; } @override string hobby() { return hobby; } @override string sign() { return sign; } @override public string tostring() { return "user{" + "name=" + name + ", " + "addr=" + addr + ", " + "age=" + age + ", " + "gender=" + gender + ", " + "hobby=" + hobby + ", " + "sign=" + sign + "}"; } @override public boolean equals(object o) { if (o == this) { return true; } if (o instanceof user) { user that = (user) o; return (this.name.equals(that.name())) && (this.addr.equals(that.addr())) && (this.age == that.age()) && (this.gender.equals(that.gender())) && (this.hobby.equals(that.hobby())) && (this.sign.equals(that.sign())); } return false; } @override public int hashcode() { int h = 1; h *= 1000003; h ^= this.name.hashcode(); h *= 1000003; h ^= this.addr.hashcode(); h *= 1000003; h ^= this.age; h *= 1000003; h ^= this.gender.hashcode(); h *= 1000003; h ^= this.hobby.hashcode(); h *= 1000003; h ^= this.sign.hashcode(); return h; } }
这个类就是生成的类,里面就帮你编写好了各种方法hashcode
、tostring
、equals
、getter
和setter
等等。
2.3 构造方法
这时候构造方法利用自己写的一个方法来实现newautovalue_user
,在user类里面添加create方法进行调用生成的autovalue_user
,这时候bean的方法这样的:
@autovalue public abstract class user { abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); //创建user,内部调用的是autovalue_user static user create(string name,string addr,int age,string gender,string hobby,string sign){ return new autovalue_user(name,addr,age,gender,hobby,sign); } }
2.4 使用
使用user.create方法即可创建对应user对象:
public class mainactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); user user = user.create("天平","广东",21,"男","敲代码","没有个性签名"); log.e("@@", "oncreate: "+user.tostring()); } }
即可看到输出
oncreate: user{name=天平, addr=广东, age=21, gender=男, hobby=敲代码, sign=没有个性签名}
三、扩展api
你以为autovalue的功能就那么少吗 ? 错,他还有很多扩展api。
3.1 auto-value-parcel
当user需要实现parcelable接口的时候,autovalue也可以帮你搞定了。
在基本的使用基础上继续导包(当前最新是0.2.5):
github地址:
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.5' // 需要自定义typeadapter就要导入 compile 'com.ryanharter.auto.value:auto-value-parcel-adapter:0.2.5'
基本parcelable
这时候把user实现接口即可:
@autovalue public abstract class user implements parcelable{ abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); static user create(string name,string addr,int age,string gender,string hobby,string sign){ return new autovalue_user(name,addr,age,gender,hobby,sign); } }
重新make一下moduel即可看到生成的autovalue_user
继承的原来的$autovalue_user
类,把parcelable
需要实现的方法放在了autovalue_user类:
final class autovalue_user extends $autovalue_user { public static final parcelable.creator<autovalue_user> creator = new parcelable.creator<autovalue_user>() { @override public autovalue_user createfromparcel(parcel in) { return new autovalue_user( in.readstring(), in.readstring(), in.readint(), in.readstring(), in.readstring(), in.readstring() ); } @override public autovalue_user[] newarray(int size) { return new autovalue_user[size]; } }; autovalue_user(string name, string addr, int age, string gender, string hobby, string sign) { super(name, addr, age, gender, hobby, sign); } @override public void writetoparcel(parcel dest, int flags) { dest.writestring(name()); dest.writestring(addr()); dest.writeint(age()); dest.writestring(gender()); dest.writestring(hobby()); dest.writestring(sign()); } @override public int describecontents() { return 0; } }
其他类型parcelable
parcel 这个扩展支持parcel类支持的所有类型,但有时您可能需要parcel其他类型,如sparsearray或arraymap。您可以使用自定义typeadapter执行此操作(需要导入auto-value-parcel-adapter)
例如user里面有一个类型date。这时候需要为date定义一个typeadapters:
public class datetypeadapter implements typeadapter<date> { public date fromparcel(parcel in) { return new date(in.readlong()); } public void toparcel(date value, parcel dest) { dest.writelong(value.gettime()); } }
然后user添加date类型:
@autovalue public abstract class user implements parcelable{ abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); //需要注解自定义的typeadapter @parceladapter(datetypeadapter.class) public abstract date date(); static user create(string name,string addr,int age,string gender,string hobby,string sign,date date){ return new autovalue_user(name,addr,age,gender,hobby,sign,date); } }
这里为延迟数据传递,新建一个secondactivity,在mainactivit传递user过去
mainactivity.java
public class mainactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); user user = user.create("天平","广东",21,"男","敲代码","没有个性签名",new date()); startactivity(new intent(this,secondactivity.class).putextra("bean",user)); } }
secondactivity.java
public class secondactivity extends activity { @override protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); user user = getintent().getparcelableextra("bean"); log.e("@@two", "oncreate: "+user.tostring()); } }
即可看到输出:
e/@@: oncreate: user{name=天平, addr=广东, age=21, gender=男, hobby=敲代码, sign=没有个性签名, date=mon mar 13 14:36:19 gmt+08:00 2017}
3.2 auto-value-gson
就是你的用了autovalues来修饰定义了bean对象,gson的就不能按照平常的方式来解析了,需要改变一下。
普及知识:
- gson的typeaapter可以理解成自定义序列化和返序列化。通过实现jsonserializer和jsondeserializer进行序列化和反序列化,在gson创建的时候registertypeadapter(你的自定义typeaapter)。 具体请百度。
auto-value-gson 的github地址:
导包(当前最新是0.4.6,注意,使用需要gson,就是也要有gson的包存在)
apt 'com.ryanharter.auto.value:auto-value-gson:0.4.6' provided 'com.ryanharter.auto.value:auto-value-gson:0.4.6' compile 'com.google.code.gson:gson:2.8.0'
3.2.1 在bean类添加typeadapter
gson解析autovalue修饰的对象,
这时候user是这样的:
@autovalue public abstract class user implements parcelable{ abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); //需要注解自定义的typeadapter @parceladapter(datetypeadapter.class) public abstract date date(); //添加一个typeadapter<user>,这个typeadapter是gson包里面的。 public static typeadapter<user> typeadapter(gson gson){ // autovalue_user.gsontypeadapter 需要先make一下module之后才会生成 return new autovalue_user.gsontypeadapter(gson) .setdefaultaddr("默认地址"); //还可以设置默认值 } }
- 注意: typeadapter,这个typeadapter是gson包里面的。autovalue_user.gsontypeadapter(gson) 需要先make一下module之后才会生成。
3.2.2 编写typeadapterfactory
然后编写对应的编写typeadapterfactory类,使用@gsontypeadapterfactory
注解去修饰。
@gsontypeadapterfactory public abstract class useradapterfactory implements typeadapterfactory { // 静态工厂方式 public static typeadapterfactory create() { return new autovaluegson_useradapterfactory(); } }
3.2.3 gson解析
上面搞好了之后,尝试来解析json为user看看。
public class mainactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); //json字符串 string json = "{\"name\":\"天平\",\"addr\":\"广东\",\"age\":21,\"gender\":\"男\",\"hobby\":\"打代码\",\"sign\":\"签名\",\"date\":\"2017-3-13 14:36:19\"}"; //初始化gson gson gson = new gsonbuilder() .registertypeadapterfactory(useradapterfactory.create()) //注册自定义的typeadapterfactory .setdateformat("yyyy-mm-dd hh:mm:ss") //设置json里面的date格式 .create(); //开始解析 user user = gson.fromjson(json,user.class); //输出结果 log.e("@@", "oncreate: "+user.tostring()); } }
即可看到:
oncreate: user{name=天平, addr=广东, age=21, gender=男, hobby=打代码, sign=签名, date=mon mar 13 14:36:19 gmt+08:00 2017}
四、小细节
4.1 gson泛型支持
如果你的bean类里面有泛型,这时候你的typeadapter也需要泛型,还要添加参数typetoken,例如:
@autovalue public abstract class foo<a, b, c> { abstract a data(); abstract list<b> datalist(); abstract map<string, list<c>> datamap(); public static <a, b, c> typeadapter<foo<a, b, c>> typeadapter(gson gson, typetoken<? extends foo<a, b, c>> typetoken) { return new autovalue_foo.gsontypeadapter(gson, typetoken); } }
4.2 可选配置
添加了下面的设置,maps/collections将默认为它们的空类型(例如list - > collections.emptylist()) 值为true或false。
apt { arguments { autovaluegson.defaultcollectionstoempty 'true' } }
4.3 autovalue plugin插件
可以生成create builder等代码,不过不能生成typeadapter代码:
插件仓库搜索: autovalue plugin
开源地址: https://github.com/afcastano/autovalueplugin
使用方法: 安装插件重启了as之后,在bean里面alt+回车 即可add
4.4 配合sqldelight
autovalue配合sqldelight效果会更好噢。
五 setter方法变种实现
autovalue修饰的类是都是immutable不变的,所以就没有了setter的方法。 我们应该怎么样补救呢?
方法1: 重新new
这种情况适用于 不是频繁的需要setter的话,重新new是个不错的方法。
例如还是上面的bean,添加了两个create方法,和builder。第二个create方法就可以用来重新new,然后setter最新的数据进来:
@autovalue public abstract class user { abstract string name(); abstract string addr(); abstract int age(); abstract string gender(); abstract string hobby(); abstract string sign(); //创建方法 public static user create(string name, string addr, int age, string gender, string hobby, string sign) { return builder() .name(name) .addr(addr) .age(age) .gender(gender) .hobby(hobby) .sign(sign) .build(); } //setter的时候传递当前的user过来,这里重新builder,再设置 public static builder create(user user){ return builder() .name(user.name()) .addr(user.addr()) .age(user.age()) .gender(user.gender()) .hobby(user.hobby()) .sign(user.sign()); } public static builder builder() { return new autovalue_user.builder(); } @autovalue.builder public abstract static class builder { public abstract builder name(string name); public abstract builder addr(string addr); public abstract builder age(int age); public abstract builder gender(string gender); public abstract builder hobby(string hobby); public abstract builder sign(string sign); public abstract user build(); } }
使用,例如我要更新签名:
private void updatesign(user user){ user = user.create(user).sign("新签名").build(); }
方法2: 不要用autovalue了
这种情况适用于你需要频繁的调用setter,如果用第一种方案的话,就需要频繁的new对象,对程序效率有大大的影响。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接
推荐阅读
-
Android下拉列表(Spinner)效果(使用C#和Java分别实现)
-
Android仿微信菜单(Menu)(使用C#和Java分别实现)
-
Android相册效果(使用C#和Java分别实现)
-
Android Studio 通过一个登录功能介绍SQLite数据库的使用
-
将Android封装库通过gradle部署到maven私服并依赖使用
-
android studio中怎么使用JNI之静态库?
-
Android Selector和Shape的使用方法
-
Android中应用界面主题Theme使用方法和页面定时跳转应用
-
Java学习笔记 DbUtils数据库查询和log4j日志输出 使用
-
MySQL数据库的使用优势、数据库类型、常用的属性约束和常用存储引擎介绍